<commit_before>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* system implementation headers */
#include <math.h>
#include <vector>

/* interface header */
#include "Region.h"

RegionPoint::RegionPoint(float x, float y)
{
  p[0] = x;
  p[1] = y;
}

RegionPoint::RegionPoint(const float v[2])
{
  p[0] = v[0];
  p[1] = v[1];
}

RegionPoint::~RegionPoint()
{
  // do nothing
}

const float* RegionPoint::get() const
{
  return p;
}

//
// BzfRegion
//
// Note: edge from corners[0] to corners[1] has neighbor stored in
// neighbors[0].  all regions should have corners ordered counter-
// clockwise.
//

BzfRegion::BzfRegion() : mailbox(0), target(0), A(0.0, 0.0)
{
}

BzfRegion::BzfRegion(int sides, const float p[][2]) :
  mailbox(0), target(0), A(0.0, 0.0)
{
  for (int i = 0; i < sides; i++) {
    corners.push_back(RegionPoint(p[i]));
    neighbors.push_back((BzfRegion*)0);
  }
}

BzfRegion::~BzfRegion()
{
  // tell neighbors I'm going away
  const int count = corners.size();
  for (int i = 0; i < count; i++)
    if (neighbors[i])
      neighbors[i]->setNeighbor(this, 0);
}

bool BzfRegion::isInside(const float p[2]) const
{
  // see if testPoint is inside my edges
  const int count = corners.size();
  if (count < 3) return false;
  bool inside = false;
  const float* p1 = corners[count - 1].get();
  const float* p2 = NULL;
  for (int i = 0; i < count; p1 = p2, i++) {
    p2 = corners[i].get();
    if (p1[1] >= p[1] && p2[1] >= p[1] || p1[1] < p[1] && p2[1] < p[1])
      continue;
    if (p1[0] < p[0] && p2[0] < p[0])
      continue;
    if (p1[0] >= p[0] && p2[0] >= p[0]) inside = !inside;
    else {
      float tolerance = (p1[1] < p2[1]) ? -0.001f : 0.001f;
      if ((p[1] - p1[1]) * (p2[0] - p1[0]) / (p2[1] - p1[1]) >=
	  p[0] - p1[0] + tolerance)
	inside = !inside;
    }
  }
  return inside;
}

float BzfRegion::getDistance(const float p[2], float nearest[2]) const
{
  const int count = corners.size();
  float currentDistance = maxDistance;
  float pointDistance;

  //compute distance from any edge
  const float* p1 = corners[count - 1].get();
  const float* p2 = NULL;
  float	d[2];
  float	m[2];
  float	t;
  float	edgeSquareDist;
  float	x, y;
  for (int c = 0; c < count; c++) {
    p2   = corners[c].get();
    d[0] = p2[0] - p1[0];
    d[1] = p2[1] - p1[1];
    m[0] = p[0]  - p1[0];
    m[1] = p[1]  - p1[1];
    edgeSquareDist = d[0] * d[0] + d[1] * d[1];
    t = (m[0] * d[0] + m[1] * d[1]) / edgeSquareDist;
    if (t <= 0) {
      pointDistance = hypotf(m[0], m[1]);
      x = p1[0];
      y = p1[1];
    } else if (t >= 1) {
      pointDistance = hypotf(m[0] - d[0], m[1] - d[1]);
      x = p2[0];
      y = p2[1];
    } else {
      pointDistance = hypotf(m[0] - t * d[0], m[1] - t * d[1]);
      x = p1[0] + t * d[0];
      y = p1[1] + t * d[1];
    }
    if (pointDistance < currentDistance) {
      currentDistance = pointDistance;
      nearest[0] = x;
      nearest[1] = y;
    }
    p1 = p2;
  }
  return currentDistance;
}

int BzfRegion::classify(const float e1[2], const float e2[2]) const
{
  // return true if all points lie to right side of edge
  const float dx = e2[0] - e1[0];
  const float dy = e2[1] - e1[1];
  const float d = dy * e1[0] - dx * e1[1];
  int toRight = 0, onEdge = 0;
  const int count = corners.size();
  for (int i = 0; i < count; i++) {
    const float* p = corners[i].get();
    const float e = -dy * p[0] + dx * p[1] + d;
    if (e < -0.00001) toRight++;
    else if (e <= 0.00001) onEdge++;
  }
  if (toRight + onEdge == count) return 1;	// all to right
  if (toRight != 0) return 0;			// not all to left -- split
  return -1;					// all to left
}

int BzfRegion::getNumSides() const
{
  return neighbors.size();
}

const RegionPoint& BzfRegion::getCorner(int index) const
{
  return corners[index];
}

BzfRegion* BzfRegion::getNeighbor(int index) const
{
  return neighbors[index];
}

BzfRegion* BzfRegion::orphanSplitRegion(const float e1[2], const float e2[2])
{
  // if edge p1,p2 intersects me then split myself along that edge.
  // return new region (the other half of the split), or NULL if no
  // split occured.  the new region (if it exists) will be to the
  // right of the cutting edge (when moving from e1 to e2).
  const int count = corners.size();
  if (count == 0) return NULL;
  int i, split = 0, edge[2];
  float tsplit[2], etsplit[2];
  const float dx = e2[0] - e1[0];
  const float dy = e2[1] - e1[1];
  const float d = dy * e1[0] - dx * e1[1];
  const float* p1 = corners[0].get();

  // Vector Product between splitter and corner : to know if right or left
  float lastPVect = d - dy * p1[0] + dx * p1[1];
  // keep sign of PVector, too risky to recompute
  bool lastSign = (lastPVect >= 0);
  // Sign (Left or Right) of first corner and hence first transition
  bool fistCornerRight = lastSign;
  for (i = 0; split < 2 && i < count; i++) {
    const float* p2 = corners[(i + 1) % count].get();
    const float pVect = d - dy * p2[0] + dx * p2[1];
    const bool newSign = (pVect >= 0);

    // if both ends of region edge are on same side of cutting edge then
    // can't intersect the edge.
    if (lastSign != newSign) {
      const float delta = lastPVect - pVect;
      // compute distance along region edge where intersection occurs
      tsplit[split] = lastPVect / delta;
      edge[split] = i;
      etsplit[split] = ((p1[1] - p2[1]) * (p1[0] - e1[0]) +
			(p2[0] - p1[0]) * (p1[1] - e1[1])) / delta;
      split++;
    }
    lastPVect = pVect;
    lastSign = newSign;
    p1 = p2;
  }

  // done if no intersections
  if (split != 2 ||
      (etsplit[0] <= 0.0 && etsplit[1] <= 0.0) ||
      (etsplit[0] >= 1.0 && etsplit[1] >= 1.0))
    return 0;

  // corner is t the left of cutting edge -- new region between edge 1 and 0
  if (!fistCornerRight) {
    i = edge[0];
    edge[0] = edge[1];
    edge[1] = i;
    float tsplitTemp = tsplit[0];
    tsplit[0] = tsplit[1];
    tsplit[1] = tsplitTemp;
  }

  // make new corners and region
  p1 = corners[edge[1]].get();
  const float* p2 = corners[(edge[1]+1) % count].get();
  RegionPoint n2(p1[0] + tsplit[1] * (p2[0] - p1[0]),
		 p1[1] + tsplit[1] * (p2[1] - p1[1]));
  p1 = corners[edge[0]].get();
  p2 = corners[(edge[0]+1) % count].get();
  RegionPoint n1(p1[0] + tsplit[0] * (p2[0] - p1[0]),
		 p1[1] + tsplit[0] * (p2[1] - p1[1]));
  BzfRegion* newRegion = new BzfRegion;

  // add sides to new region and remove them from me.  the new region
  // must be to the right of the edge.  see if the corner after the
  // split on the first split edge is to the right or left of the
  // cutting edge.
  {
    // add sides to new region
    newRegion->addSide(n1, neighbors[edge[0]]);
    i = edge[0];
    while (true) {
      i++;
      if (i == count)
	i = 0;
      newRegion->addSide(corners[i], neighbors[i]);
      if (i == edge[1])
	break;
      if (neighbors[i]) neighbors[i]->setNeighbor(this, newRegion);
    }
    newRegion->addSide(n2, this);

    // tell neighbors on split edges to split the shared edge at the
    // same place and to point to their new neighbor
    // tell them about their new neighbor.
    if (neighbors[edge[0]])
      neighbors[edge[0]]->splitEdge(this, newRegion, n1, true);
    if (neighbors[edge[1]])
      neighbors[edge[1]]->splitEdge(this, newRegion, n2, false);

    // remove old edges from myself and add new ones
    std::vector<RegionPoint> newCorners;
    std::vector<BzfRegion*> newNeighbors;
    newCorners.push_back(n2);
    newNeighbors.push_back(neighbors[edge[1]]);
    i = edge[1];
    while (true) {
      i++;
      if (i == count)
	i = 0;
      newCorners.push_back(corners[i]);
      newNeighbors.push_back(neighbors[i]);
      if (i == edge[0])
	break;
    }
    newCorners.push_back(n1);
    newNeighbors.push_back(newRegion);
    corners = newCorners;
    neighbors = newNeighbors;
  }

  // throw out degenerate edges in myself and newRegion
  tidy();
  newRegion->tidy();

  // all done
  return newRegion;
}

void BzfRegion::splitEdge(const BzfRegion* oldNeighbor,
			  BzfRegion* newNeighbor,
			  const RegionPoint& p,
			  bool onRight)
{
  // split my edge which has neighbor oldNeighbor at point p.
  // set the neighbor for the edge on the right if onRight is true
  // or on the left if onRight is false to newNeighbor.
  const int count = corners.size();
  for (int i = 0; i < count; i++)
    if (neighbors[i] == oldNeighbor) {
      std::vector<RegionPoint>::iterator it1 = corners.begin();
      for(int j = 0; j < i + 1; j++) it1++;
      corners.insert(it1, p);
      if (onRight) {
	std::vector<BzfRegion*>::iterator it2 = neighbors.begin();
	for(int j = 0; j < i; j++) it2++;
	neighbors.insert(it2, newNeighbor);
      }
      else {
	std::vector<BzfRegion*>::iterator it2 = neighbors.begin();
	for(int j = 0; j < i + 1; j++) it2++;
	neighbors.insert(it2, newNeighbor);
      }
      tidy();
      break;
    }
}

void BzfRegion::addSide(const RegionPoint& p, BzfRegion* neighbor)
{
  corners.push_back(p);
  neighbors.push_back(neighbor);
}

void BzfRegion::setNeighbor(const BzfRegion* oldNeighbor,
			    BzfRegion* newNeighbor)
{
  const int count = corners.size();
  for (int i = 0; i < count; i++)
    if (neighbors[i] == oldNeighbor) {
      neighbors[i] = newNeighbor;
      break;
    }
}

void BzfRegion::tidy()
{
  // throw out degenerate edges
  int count = corners.size();
  for (int i = 0; i < count; i++) {
    const float* p1 = corners[i].get();
    const float* p2 = corners[(i+1)%count].get();
    if (fabs(p1[0] - p2[0]) < ZERO_TOLERANCE && fabs(p1[1] - p2[1]) < ZERO_TOLERANCE) {
      std::vector<RegionPoint>::iterator it1 = corners.begin();
      for(int j = 0; j < i; j++) it1++;
      corners.erase(it1);
      std::vector<BzfRegion*>::iterator it2 = neighbors.begin();
      for(int k = 0; k < i; k++) it2++;
      neighbors.erase(it2);
      i--;
      count--;
    }
  }
}

bool BzfRegion::test(int mailboxIndex)
{
  return (mailbox != mailboxIndex);
}

void BzfRegion::setPathStuff(float _distance,
			     BzfRegion* _target,
			     const float _a[2], int mailboxIndex)
{
  distance = _distance;
  target = _target;
  A = RegionPoint(_a);
  mailbox = mailboxIndex;
}

float BzfRegion::getDistance() const
{
  return distance;
}

BzfRegion* BzfRegion::getTarget() const
{
  return target;
}

const float* BzfRegion::getA() const
{
  return A.get();
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>class interface headers come before system implementation headers<commit_after>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* interface header */
#include "Region.h"

/* system implementation headers */
#include <math.h>
#include <vector>

RegionPoint::RegionPoint(float x, float y)
{
  p[0] = x;
  p[1] = y;
}

RegionPoint::RegionPoint(const float v[2])
{
  p[0] = v[0];
  p[1] = v[1];
}

RegionPoint::~RegionPoint()
{
  // do nothing
}

const float* RegionPoint::get() const
{
  return p;
}

//
// BzfRegion
//
// Note: edge from corners[0] to corners[1] has neighbor stored in
// neighbors[0].  all regions should have corners ordered counter-
// clockwise.
//

BzfRegion::BzfRegion() : mailbox(0), target(0), A(0.0, 0.0)
{
}

BzfRegion::BzfRegion(int sides, const float p[][2]) :
  mailbox(0), target(0), A(0.0, 0.0)
{
  for (int i = 0; i < sides; i++) {
    corners.push_back(RegionPoint(p[i]));
    neighbors.push_back((BzfRegion*)0);
  }
}

BzfRegion::~BzfRegion()
{
  // tell neighbors I'm going away
  const int count = corners.size();
  for (int i = 0; i < count; i++)
    if (neighbors[i])
      neighbors[i]->setNeighbor(this, 0);
}

bool BzfRegion::isInside(const float p[2]) const
{
  // see if testPoint is inside my edges
  const int count = corners.size();
  if (count < 3) return false;
  bool inside = false;
  const float* p1 = corners[count - 1].get();
  const float* p2 = NULL;
  for (int i = 0; i < count; p1 = p2, i++) {
    p2 = corners[i].get();
    if (p1[1] >= p[1] && p2[1] >= p[1] || p1[1] < p[1] && p2[1] < p[1])
      continue;
    if (p1[0] < p[0] && p2[0] < p[0])
      continue;
    if (p1[0] >= p[0] && p2[0] >= p[0]) inside = !inside;
    else {
      float tolerance = (p1[1] < p2[1]) ? -0.001f : 0.001f;
      if ((p[1] - p1[1]) * (p2[0] - p1[0]) / (p2[1] - p1[1]) >=
	  p[0] - p1[0] + tolerance)
	inside = !inside;
    }
  }
  return inside;
}

float BzfRegion::getDistance(const float p[2], float nearest[2]) const
{
  const int count = corners.size();
  float currentDistance = maxDistance;
  float pointDistance;

  //compute distance from any edge
  const float* p1 = corners[count - 1].get();
  const float* p2 = NULL;
  float	d[2];
  float	m[2];
  float	t;
  float	edgeSquareDist;
  float	x, y;
  for (int c = 0; c < count; c++) {
    p2   = corners[c].get();
    d[0] = p2[0] - p1[0];
    d[1] = p2[1] - p1[1];
    m[0] = p[0]  - p1[0];
    m[1] = p[1]  - p1[1];
    edgeSquareDist = d[0] * d[0] + d[1] * d[1];
    t = (m[0] * d[0] + m[1] * d[1]) / edgeSquareDist;
    if (t <= 0) {
      pointDistance = hypotf(m[0], m[1]);
      x = p1[0];
      y = p1[1];
    } else if (t >= 1) {
      pointDistance = hypotf(m[0] - d[0], m[1] - d[1]);
      x = p2[0];
      y = p2[1];
    } else {
      pointDistance = hypotf(m[0] - t * d[0], m[1] - t * d[1]);
      x = p1[0] + t * d[0];
      y = p1[1] + t * d[1];
    }
    if (pointDistance < currentDistance) {
      currentDistance = pointDistance;
      nearest[0] = x;
      nearest[1] = y;
    }
    p1 = p2;
  }
  return currentDistance;
}

int BzfRegion::classify(const float e1[2], const float e2[2]) const
{
  // return true if all points lie to right side of edge
  const float dx = e2[0] - e1[0];
  const float dy = e2[1] - e1[1];
  const float d = dy * e1[0] - dx * e1[1];
  int toRight = 0, onEdge = 0;
  const int count = corners.size();
  for (int i = 0; i < count; i++) {
    const float* p = corners[i].get();
    const float e = -dy * p[0] + dx * p[1] + d;
    if (e < -0.00001) toRight++;
    else if (e <= 0.00001) onEdge++;
  }
  if (toRight + onEdge == count) return 1;	// all to right
  if (toRight != 0) return 0;			// not all to left -- split
  return -1;					// all to left
}

int BzfRegion::getNumSides() const
{
  return neighbors.size();
}

const RegionPoint& BzfRegion::getCorner(int index) const
{
  return corners[index];
}

BzfRegion* BzfRegion::getNeighbor(int index) const
{
  return neighbors[index];
}

BzfRegion* BzfRegion::orphanSplitRegion(const float e1[2], const float e2[2])
{
  // if edge p1,p2 intersects me then split myself along that edge.
  // return new region (the other half of the split), or NULL if no
  // split occured.  the new region (if it exists) will be to the
  // right of the cutting edge (when moving from e1 to e2).
  const int count = corners.size();
  if (count == 0) return NULL;
  int i, split = 0, edge[2];
  float tsplit[2], etsplit[2];
  const float dx = e2[0] - e1[0];
  const float dy = e2[1] - e1[1];
  const float d = dy * e1[0] - dx * e1[1];
  const float* p1 = corners[0].get();

  // Vector Product between splitter and corner : to know if right or left
  float lastPVect = d - dy * p1[0] + dx * p1[1];
  // keep sign of PVector, too risky to recompute
  bool lastSign = (lastPVect >= 0);
  // Sign (Left or Right) of first corner and hence first transition
  bool fistCornerRight = lastSign;
  for (i = 0; split < 2 && i < count; i++) {
    const float* p2 = corners[(i + 1) % count].get();
    const float pVect = d - dy * p2[0] + dx * p2[1];
    const bool newSign = (pVect >= 0);

    // if both ends of region edge are on same side of cutting edge then
    // can't intersect the edge.
    if (lastSign != newSign) {
      const float delta = lastPVect - pVect;
      // compute distance along region edge where intersection occurs
      tsplit[split] = lastPVect / delta;
      edge[split] = i;
      etsplit[split] = ((p1[1] - p2[1]) * (p1[0] - e1[0]) +
			(p2[0] - p1[0]) * (p1[1] - e1[1])) / delta;
      split++;
    }
    lastPVect = pVect;
    lastSign = newSign;
    p1 = p2;
  }

  // done if no intersections
  if (split != 2 ||
      (etsplit[0] <= 0.0 && etsplit[1] <= 0.0) ||
      (etsplit[0] >= 1.0 && etsplit[1] >= 1.0))
    return 0;

  // corner is t the left of cutting edge -- new region between edge 1 and 0
  if (!fistCornerRight) {
    i = edge[0];
    edge[0] = edge[1];
    edge[1] = i;
    float tsplitTemp = tsplit[0];
    tsplit[0] = tsplit[1];
    tsplit[1] = tsplitTemp;
  }

  // make new corners and region
  p1 = corners[edge[1]].get();
  const float* p2 = corners[(edge[1]+1) % count].get();
  RegionPoint n2(p1[0] + tsplit[1] * (p2[0] - p1[0]),
		 p1[1] + tsplit[1] * (p2[1] - p1[1]));
  p1 = corners[edge[0]].get();
  p2 = corners[(edge[0]+1) % count].get();
  RegionPoint n1(p1[0] + tsplit[0] * (p2[0] - p1[0]),
		 p1[1] + tsplit[0] * (p2[1] - p1[1]));
  BzfRegion* newRegion = new BzfRegion;

  // add sides to new region and remove them from me.  the new region
  // must be to the right of the edge.  see if the corner after the
  // split on the first split edge is to the right or left of the
  // cutting edge.
  {
    // add sides to new region
    newRegion->addSide(n1, neighbors[edge[0]]);
    i = edge[0];
    while (true) {
      i++;
      if (i == count)
	i = 0;
      newRegion->addSide(corners[i], neighbors[i]);
      if (i == edge[1])
	break;
      if (neighbors[i]) neighbors[i]->setNeighbor(this, newRegion);
    }
    newRegion->addSide(n2, this);

    // tell neighbors on split edges to split the shared edge at the
    // same place and to point to their new neighbor
    // tell them about their new neighbor.
    if (neighbors[edge[0]])
      neighbors[edge[0]]->splitEdge(this, newRegion, n1, true);
    if (neighbors[edge[1]])
      neighbors[edge[1]]->splitEdge(this, newRegion, n2, false);

    // remove old edges from myself and add new ones
    std::vector<RegionPoint> newCorners;
    std::vector<BzfRegion*> newNeighbors;
    newCorners.push_back(n2);
    newNeighbors.push_back(neighbors[edge[1]]);
    i = edge[1];
    while (true) {
      i++;
      if (i == count)
	i = 0;
      newCorners.push_back(corners[i]);
      newNeighbors.push_back(neighbors[i]);
      if (i == edge[0])
	break;
    }
    newCorners.push_back(n1);
    newNeighbors.push_back(newRegion);
    corners = newCorners;
    neighbors = newNeighbors;
  }

  // throw out degenerate edges in myself and newRegion
  tidy();
  newRegion->tidy();

  // all done
  return newRegion;
}

void BzfRegion::splitEdge(const BzfRegion* oldNeighbor,
			  BzfRegion* newNeighbor,
			  const RegionPoint& p,
			  bool onRight)
{
  // split my edge which has neighbor oldNeighbor at point p.
  // set the neighbor for the edge on the right if onRight is true
  // or on the left if onRight is false to newNeighbor.
  const int count = corners.size();
  for (int i = 0; i < count; i++)
    if (neighbors[i] == oldNeighbor) {
      std::vector<RegionPoint>::iterator it1 = corners.begin();
      for(int j = 0; j < i + 1; j++) it1++;
      corners.insert(it1, p);
      if (onRight) {
	std::vector<BzfRegion*>::iterator it2 = neighbors.begin();
	for(int j = 0; j < i; j++) it2++;
	neighbors.insert(it2, newNeighbor);
      }
      else {
	std::vector<BzfRegion*>::iterator it2 = neighbors.begin();
	for(int j = 0; j < i + 1; j++) it2++;
	neighbors.insert(it2, newNeighbor);
      }
      tidy();
      break;
    }
}

void BzfRegion::addSide(const RegionPoint& p, BzfRegion* neighbor)
{
  corners.push_back(p);
  neighbors.push_back(neighbor);
}

void BzfRegion::setNeighbor(const BzfRegion* oldNeighbor,
			    BzfRegion* newNeighbor)
{
  const int count = corners.size();
  for (int i = 0; i < count; i++)
    if (neighbors[i] == oldNeighbor) {
      neighbors[i] = newNeighbor;
      break;
    }
}

void BzfRegion::tidy()
{
  // throw out degenerate edges
  int count = corners.size();
  for (int i = 0; i < count; i++) {
    const float* p1 = corners[i].get();
    const float* p2 = corners[(i+1)%count].get();
    if (fabs(p1[0] - p2[0]) < ZERO_TOLERANCE && fabs(p1[1] - p2[1]) < ZERO_TOLERANCE) {
      std::vector<RegionPoint>::iterator it1 = corners.begin();
      for(int j = 0; j < i; j++) it1++;
      corners.erase(it1);
      std::vector<BzfRegion*>::iterator it2 = neighbors.begin();
      for(int k = 0; k < i; k++) it2++;
      neighbors.erase(it2);
      i--;
      count--;
    }
  }
}

bool BzfRegion::test(int mailboxIndex)
{
  return (mailbox != mailboxIndex);
}

void BzfRegion::setPathStuff(float _distance,
			     BzfRegion* _target,
			     const float _a[2], int mailboxIndex)
{
  distance = _distance;
  target = _target;
  A = RegionPoint(_a);
  mailbox = mailboxIndex;
}

float BzfRegion::getDistance() const
{
  return distance;
}

BzfRegion* BzfRegion::getTarget() const
{
  return target;
}

const float* BzfRegion::getA() const
{
  return A.get();
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#ifndef CAN_EMULATOR

#include "interface/usb.h"
#include "can/canread.h"
#include "interface/uart.h"
#include "interface/network.h"
#include "signals.h"
#include "util/log.h"
#include "cJSON.h"
#include "interface/pipeline.h"
#include "util/timer.h"
#include "lights.h"
#include "power.h"
#include "bluetooth.h"
#include "platform/platform.h"
#include <stdint.h>
#include <stdlib.h>

using openxc::can::canBusActive;
using openxc::can::initializeCan;
using openxc::can::write::processCanWriteQueue;
using openxc::can::write::sendCanSignal;
using openxc::can::write::enqueueCanMessage;
using openxc::can::lookupCommand;
using openxc::can::lookupSignal;
using openxc::lights::LIGHT_A;
using openxc::lights::LIGHT_B;
using openxc::lights::COLORS;
using openxc::util::time::systemTimeMs;
using openxc::signals::initializeSignals;
using openxc::signals::getCanBuses;
using openxc::signals::getCanBusCount;
using openxc::signals::getCommands;
using openxc::signals::getCommandCount;
using openxc::signals::getSignals;
using openxc::signals::getSignalCount;
using openxc::signals::decodeCanMessage;
using openxc::platform::suspend;

extern Listener listener;

/* Forward declarations */

void receiveCan(Listener*, CanBus*);
void initializeAllCan();
bool receiveWriteRequest(uint8_t*);
void updateDataLights();

void setup() {
    initializeAllCan();
    initializeSignals();
}

void loop() {
    for(int i = 0; i < getCanBusCount(); i++) {
        receiveCan(&listener, &getCanBuses()[i]);
    }

    readFromHost(listener.usb, receiveWriteRequest);
    readFromSerial(listener.serial, receiveWriteRequest);
    readFromSocket(listener.network, receiveWriteRequest);

    for(int i = 0; i < getCanBusCount(); i++) {
        processCanWriteQueue(&getCanBuses()[i]);
    }

    updateDataLights();
    openxc::signals::loop();
}

/* Public: Update the color and status of a board's light that shows the status
 * of the CAN bus. This function is intended to be called each time through the
 * main program loop.
 */
void updateDataLights() {
    static unsigned long startupTime = systemTimeMs();
    static bool busWasActive;
    bool busActive = false;
    for(int i = 0; i < getCanBusCount(); i++) {
        busActive = busActive || canBusActive(&getCanBuses()[i]);
    }

    if(!busWasActive && busActive) {
        debug("CAN woke up - enabling LED");
        enable(LIGHT_A, COLORS.blue);
        busWasActive = true;
    } else if(!busActive && busWasActive && systemTimeMs() - startupTime >
            (unsigned long)openxc::can::CAN_ACTIVE_TIMEOUT_S * 1000) {
        // stay awake at least CAN_ACTIVE_TIMEOUT_S after power on
#ifndef TRANSMITTER
        busWasActive = false;
        suspend(&listener);
#endif
    }
}

void initializeAllCan() {
    for(int i = 0; i < getCanBusCount(); i++) {
        initializeCan(&(getCanBuses()[i]));
    }
}

void receiveRawWriteRequest(cJSON* idObject, cJSON* root) {
    uint32_t id = idObject->valueint;
    cJSON* dataObject = cJSON_GetObjectItem(root, "data");
    if(dataObject == NULL) {
        debug("Raw write request missing data", id);
        return;
    }

    char* dataString = dataObject->valuestring;
    char* end;
    // TODO hard coding bus 0 right now, but it should support sending on either
    CanMessage message = {&getCanBuses()[0], id};
    enqueueCanMessage(&message, strtoull(dataString, &end, 16));
}

void receiveTranslatedWriteRequest(cJSON* nameObject, cJSON* root) {
    char* name = nameObject->valuestring;
    cJSON* value = cJSON_GetObjectItem(root, "value");

    // Optional, may be NULL
    cJSON* event = cJSON_GetObjectItem(root, "event");

    CanSignal* signal = lookupSignal(name, getSignals(), getSignalCount(),
            true);
    if(signal != NULL) {
        if(value == NULL) {
            debug("Write request for %s missing value", name);
            return;
        }
        sendCanSignal(signal, value, getSignals(), getSignalCount());
    } else {
        CanCommand* command = lookupCommand(name, getCommands(),
                getCommandCount());
        if(command != NULL) {
            command->handler(name, value, event, getSignals(),
                    getSignalCount());
        } else {
            debug("Writing not allowed for signal with name %s", name);
        }
    }
}

bool receiveWriteRequest(uint8_t* message) {
    cJSON *root = cJSON_Parse((char*)message);
    bool foundMessage = false;
    if(root != NULL) {
        foundMessage = true;
        cJSON* nameObject = cJSON_GetObjectItem(root, "name");
        if(nameObject == NULL) {
            cJSON* idObject = cJSON_GetObjectItem(root, "id");
            if(idObject == NULL) {
                debug("Write request is malformed, "
                        "missing name or id: %s", message);
            } else {
                receiveRawWriteRequest(idObject, root);
            }
        } else {
            receiveTranslatedWriteRequest(nameObject, root);
        }
        cJSON_Delete(root);
    } else {
        debug("No valid JSON in incoming buffer yet -- "
                "if it's valid, may be out of memory");
    }
    return foundMessage;
}

/*
 * Check to see if a packet has been received. If so, read the packet and print
 * the packet payload to the serial monitor.
 */
void receiveCan(Listener* listener, CanBus* bus) {
    // TODO what happens if we process until the queue is empty?
    if(!QUEUE_EMPTY(CanMessage, &bus->receiveQueue)) {
        CanMessage message = QUEUE_POP(CanMessage, &bus->receiveQueue);
        decodeCanMessage(listener, bus, message.id, message.data);
        bus->lastMessageReceived = systemTimeMs();
    }
}

void reset() {
    initializeAllCan();
}

#endif // CAN_EMULATOR
<commit_msg>Suspend after 30s if no CAN activity on startup.<commit_after>#ifndef CAN_EMULATOR

#include "interface/usb.h"
#include "can/canread.h"
#include "interface/uart.h"
#include "interface/network.h"
#include "signals.h"
#include "util/log.h"
#include "cJSON.h"
#include "interface/pipeline.h"
#include "util/timer.h"
#include "lights.h"
#include "power.h"
#include "bluetooth.h"
#include "platform/platform.h"
#include <stdint.h>
#include <stdlib.h>

using openxc::can::canBusActive;
using openxc::can::initializeCan;
using openxc::can::write::processCanWriteQueue;
using openxc::can::write::sendCanSignal;
using openxc::can::write::enqueueCanMessage;
using openxc::can::lookupCommand;
using openxc::can::lookupSignal;
using openxc::lights::LIGHT_A;
using openxc::lights::LIGHT_B;
using openxc::lights::COLORS;
using openxc::util::time::systemTimeMs;
using openxc::signals::initializeSignals;
using openxc::signals::getCanBuses;
using openxc::signals::getCanBusCount;
using openxc::signals::getCommands;
using openxc::signals::getCommandCount;
using openxc::signals::getSignals;
using openxc::signals::getSignalCount;
using openxc::signals::decodeCanMessage;
using openxc::platform::suspend;

extern Listener listener;

/* Forward declarations */

void receiveCan(Listener*, CanBus*);
void initializeAllCan();
bool receiveWriteRequest(uint8_t*);
void updateDataLights();

void setup() {
    initializeAllCan();
    initializeSignals();
}

void loop() {
    for(int i = 0; i < getCanBusCount(); i++) {
        receiveCan(&listener, &getCanBuses()[i]);
    }

    readFromHost(listener.usb, receiveWriteRequest);
    readFromSerial(listener.serial, receiveWriteRequest);
    readFromSocket(listener.network, receiveWriteRequest);

    for(int i = 0; i < getCanBusCount(); i++) {
        processCanWriteQueue(&getCanBuses()[i]);
    }

    updateDataLights();
    openxc::signals::loop();
}

/* Public: Update the color and status of a board's light that shows the status
 * of the CAN bus. This function is intended to be called each time through the
 * main program loop.
 */
void updateDataLights() {
    static unsigned long startupTime = systemTimeMs();
    static bool busWasActive;
    bool busActive = false;
    for(int i = 0; i < getCanBusCount(); i++) {
        busActive = busActive || canBusActive(&getCanBuses()[i]);
    }

    if(!busWasActive && busActive) {
        debug("CAN woke up - enabling LED");
        enable(LIGHT_A, COLORS.blue);
        busWasActive = true;
    } else if(!busActive && (busWasActive || systemTimeMs() - startupTime >
            (unsigned long)openxc::can::CAN_ACTIVE_TIMEOUT_S * 1000)) {
        // stay awake at least CAN_ACTIVE_TIMEOUT_S after power on
#ifndef TRANSMITTER
        busWasActive = false;
        suspend(&listener);
#endif
    }
}

void initializeAllCan() {
    for(int i = 0; i < getCanBusCount(); i++) {
        initializeCan(&(getCanBuses()[i]));
    }
}

void receiveRawWriteRequest(cJSON* idObject, cJSON* root) {
    uint32_t id = idObject->valueint;
    cJSON* dataObject = cJSON_GetObjectItem(root, "data");
    if(dataObject == NULL) {
        debug("Raw write request missing data", id);
        return;
    }

    char* dataString = dataObject->valuestring;
    char* end;
    // TODO hard coding bus 0 right now, but it should support sending on either
    CanMessage message = {&getCanBuses()[0], id};
    enqueueCanMessage(&message, strtoull(dataString, &end, 16));
}

void receiveTranslatedWriteRequest(cJSON* nameObject, cJSON* root) {
    char* name = nameObject->valuestring;
    cJSON* value = cJSON_GetObjectItem(root, "value");

    // Optional, may be NULL
    cJSON* event = cJSON_GetObjectItem(root, "event");

    CanSignal* signal = lookupSignal(name, getSignals(), getSignalCount(),
            true);
    if(signal != NULL) {
        if(value == NULL) {
            debug("Write request for %s missing value", name);
            return;
        }
        sendCanSignal(signal, value, getSignals(), getSignalCount());
    } else {
        CanCommand* command = lookupCommand(name, getCommands(),
                getCommandCount());
        if(command != NULL) {
            command->handler(name, value, event, getSignals(),
                    getSignalCount());
        } else {
            debug("Writing not allowed for signal with name %s", name);
        }
    }
}

bool receiveWriteRequest(uint8_t* message) {
    cJSON *root = cJSON_Parse((char*)message);
    bool foundMessage = false;
    if(root != NULL) {
        foundMessage = true;
        cJSON* nameObject = cJSON_GetObjectItem(root, "name");
        if(nameObject == NULL) {
            cJSON* idObject = cJSON_GetObjectItem(root, "id");
            if(idObject == NULL) {
                debug("Write request is malformed, "
                        "missing name or id: %s", message);
            } else {
                receiveRawWriteRequest(idObject, root);
            }
        } else {
            receiveTranslatedWriteRequest(nameObject, root);
        }
        cJSON_Delete(root);
    } else {
        debug("No valid JSON in incoming buffer yet -- "
                "if it's valid, may be out of memory");
    }
    return foundMessage;
}

/*
 * Check to see if a packet has been received. If so, read the packet and print
 * the packet payload to the serial monitor.
 */
void receiveCan(Listener* listener, CanBus* bus) {
    // TODO what happens if we process until the queue is empty?
    if(!QUEUE_EMPTY(CanMessage, &bus->receiveQueue)) {
        CanMessage message = QUEUE_POP(CanMessage, &bus->receiveQueue);
        decodeCanMessage(listener, bus, message.id, message.data);
        bus->lastMessageReceived = systemTimeMs();
    }
}

void reset() {
    initializeAllCan();
}

#endif // CAN_EMULATOR
<|endoftext|>


<commit_before>
#include "lockdep.h"

#include "include/types.h"
#include "Clock.h"
#include "BackTrace.h"

#include <ext/hash_map>

#include "config.h"

#undef dout
#define  dout(l)    if (l<=g_conf.debug_lockdep) *_dout << g_clock.now() << " " << std::hex << pthread_self() << std::dec << " lockdep: "

#undef dendl
#define dendl std::endl

// global
int g_lockdep = 0;

// disable lockdep when this module destructs.
struct lockdep_stopper_t {
  ~lockdep_stopper_t() {
    g_lockdep = 0;
  }
};

static lockdep_stopper_t lockdep_stopper;

pthread_mutex_t lockdep_mutex = PTHREAD_MUTEX_INITIALIZER;

#define MAX_LOCKS  100   // increase me as needed

hash_map<const char *, int> lock_ids;
map<int, const char *> lock_names;

int last_id = 0;

hash_map<pthread_t, map<int,BackTrace*> > held;
BackTrace *follows[MAX_LOCKS][MAX_LOCKS];       // follows[a][b] means b taken after a

#define BACKTRACE_SKIP 3

int lockdep_dump_locks()
{
  pthread_mutex_lock(&lockdep_mutex);

  for (hash_map<pthread_t, map<int,BackTrace*> >::iterator p = held.begin();
       p != held.end();
       p++) {
    dout(0) << "--- thread " << p->first << " ---" << dendl;
    for (map<int,BackTrace*>::iterator q = p->second.begin();
	 q != p->second.end();
	 q++) {
      dout(0) << "  * " << lock_names[q->first] << "\n";
      if (q->second)
	q->second->print(*_dout);
      *_dout << dendl;
    }
  }

  pthread_mutex_unlock(&lockdep_mutex);
  return 0;
}

int lockdep_register(const char *name)
{
  int id;

  pthread_mutex_lock(&lockdep_mutex);

  if (last_id == 0)
    for (int i=0; i<MAX_LOCKS; i++)
      for (int j=0; j<MAX_LOCKS; j++)
	follows[i][j] = NULL;

  hash_map<const char *, int>::iterator p = lock_ids.find(name);
  if (p == lock_ids.end()) {
    assert(last_id < MAX_LOCKS);
    id = last_id++;
    lock_ids[name] = id;
    lock_names[id] = name;
    dout(10) << "registered '" << name << "' as " << id << dendl;
  } else {
    id = p->second;
    dout(20) << "had '" << name << "' as " << id << dendl;
  }

  pthread_mutex_unlock(&lockdep_mutex);

  return id;
}

// does a follow b?
static bool does_follow(int a, int b)
{
  if (follows[a][b]) {
    dout(0) << "\n";
    *_dout << "------------------------------------" << "\n";
    *_dout << "existing dependency " << lock_names[a] << " (" << a << ") -> "
           << lock_names[b] << " (" << b << ") at:\n";
    follows[a][b]->print(*_dout);
    *_dout << dendl;
    return true;
  }

  for (int i=0; i<MAX_LOCKS; i++) {
    if (follows[a][i] &&
	does_follow(i, b)) {
      dout(0) << "existing intermediate dependency " << lock_names[a]
          << " (" << a << ") -> " << lock_names[i] << " (" << i << ") at:\n";
      follows[a][i]->print(*_dout);
      *_dout << dendl;
      return true;
    }
  }

  return false;
}

int lockdep_will_lock(const char *name, int id)
{
  pthread_t p = pthread_self();
  if (id < 0) id = lockdep_register(name);

  pthread_mutex_lock(&lockdep_mutex);
  dout(20) << "_will_lock " << name << " (" << id << ")" << dendl;

  // check dependency graph
  map<int, BackTrace *> &m = held[p];
  for (map<int, BackTrace *>::iterator p = m.begin();
       p != m.end();
       p++) {
    if (p->first == id) {
      dout(0) << "\n";
      *_dout << "recursive lock of " << name << " (" << id << ")\n";
      BackTrace *bt = new BackTrace(BACKTRACE_SKIP);
      bt->print(*_dout);
      if (p->second) {
	*_dout << "\npreviously locked at\n";
	p->second->print(*_dout);
      }
      *_dout << dendl;
      assert(0);
    }
    else if (!follows[p->first][id]) {
      // new dependency

      // did we just create a cycle?
      BackTrace *bt = new BackTrace(BACKTRACE_SKIP);
      if (does_follow(id, p->first)) {
	dout(0) << "new dependency " << lock_names[p->first]
		<< " (" << p->first << ") -> " << name << " (" << id << ")"
		<< " creates a cycle at\n";
	bt->print(*_dout);
	*_dout << dendl;

	dout(0) << "btw, i am holding these locks:" << dendl;
	for (map<int, BackTrace *>::iterator q = m.begin();
	     q != m.end();
	     q++) {
	  dout(0) << "  " << lock_names[q->first] << " (" << q->first << ")" << dendl;
	  if (q->second) {
	    dout(0) << " ";
	    q->second->print(*_dout);
	    *_dout << dendl;
	  }
	}

	dout(0) << "\n" << dendl;

	// don't add this dependency, or we'll get aMutex. cycle in the graph, and
	// does_follow() won't terminate.

	assert(0);  // actually, we should just die here.
      } else {
	follows[p->first][id] = bt;
	dout(10) << lock_names[p->first] << " -> " << name << " at" << dendl;
	//bt->print(*_dout);
      }
    }
  }

  pthread_mutex_unlock(&lockdep_mutex);
  return id;
}

int lockdep_locked(const char *name, int id, bool force_backtrace)
{
  pthread_t p = pthread_self();

  if (id < 0) id = lockdep_register(name);

  pthread_mutex_lock(&lockdep_mutex);
  dout(20) << "_locked " << name << dendl;
  if (g_lockdep >= 2 || force_backtrace)
    held[p][id] = new BackTrace(BACKTRACE_SKIP);
  else
    held[p][id] = 0;
  pthread_mutex_unlock(&lockdep_mutex);
  return id;
}

int lockdep_will_unlock(const char *name, int id)
{
  pthread_t p = pthread_self();

  if (id < 0) {
    //id = lockdep_register(name);
    assert(id == -1);
    return id;
  }

  pthread_mutex_lock(&lockdep_mutex);
  dout(20) << "_will_unlock " << name << dendl;

  // don't assert.. lockdep may be enabled at any point in time
  //assert(held.count(p));
  //assert(held[p].count(id));

  delete held[p][id];
  held[p].erase(id);
  pthread_mutex_unlock(&lockdep_mutex);
  return id;
}

<commit_msg>common/lockdep.cc: don't use dout unlocked<commit_after>
#include "lockdep.h"

#include "include/types.h"
#include "Clock.h"
#include "BackTrace.h"

#include <ext/hash_map>

#include "config.h"

#define DOUT_SUBSYS lockdep

// global
int g_lockdep = 0;

// disable lockdep when this module destructs.
struct lockdep_stopper_t {
  ~lockdep_stopper_t() {
    g_lockdep = 0;
  }
};

static lockdep_stopper_t lockdep_stopper;

pthread_mutex_t lockdep_mutex = PTHREAD_MUTEX_INITIALIZER;

#define MAX_LOCKS  100   // increase me as needed

hash_map<const char *, int> lock_ids;
map<int, const char *> lock_names;

int last_id = 0;

hash_map<pthread_t, map<int,BackTrace*> > held;
BackTrace *follows[MAX_LOCKS][MAX_LOCKS];       // follows[a][b] means b taken after a

#define BACKTRACE_SKIP 3

int lockdep_dump_locks()
{
  pthread_mutex_lock(&lockdep_mutex);

  for (hash_map<pthread_t, map<int,BackTrace*> >::iterator p = held.begin();
       p != held.end();
       p++) {
    dout(0) << "--- thread " << p->first << " ---" << dendl;
    for (map<int,BackTrace*>::iterator q = p->second.begin();
	 q != p->second.end();
	 q++) {
      dout(0) << "  * " << lock_names[q->first] << "\n";
      if (q->second)
	q->second->print(*_dout);
      *_dout << dendl;
    }
  }

  pthread_mutex_unlock(&lockdep_mutex);
  return 0;
}

int lockdep_register(const char *name)
{
  int id;

  pthread_mutex_lock(&lockdep_mutex);

  if (last_id == 0)
    for (int i=0; i<MAX_LOCKS; i++)
      for (int j=0; j<MAX_LOCKS; j++)
	follows[i][j] = NULL;

  hash_map<const char *, int>::iterator p = lock_ids.find(name);
  if (p == lock_ids.end()) {
    assert(last_id < MAX_LOCKS);
    id = last_id++;
    lock_ids[name] = id;
    lock_names[id] = name;
    dout(10) << "registered '" << name << "' as " << id << dendl;
  } else {
    id = p->second;
    dout(20) << "had '" << name << "' as " << id << dendl;
  }

  pthread_mutex_unlock(&lockdep_mutex);

  return id;
}

// does a follow b?
static bool does_follow(int a, int b)
{
  if (follows[a][b]) {
    dout(0) << "\n";
    *_dout << "------------------------------------" << "\n";
    *_dout << "existing dependency " << lock_names[a] << " (" << a << ") -> "
           << lock_names[b] << " (" << b << ") at:\n";
    follows[a][b]->print(*_dout);
    *_dout << dendl;
    return true;
  }

  for (int i=0; i<MAX_LOCKS; i++) {
    if (follows[a][i] &&
	does_follow(i, b)) {
      dout(0) << "existing intermediate dependency " << lock_names[a]
          << " (" << a << ") -> " << lock_names[i] << " (" << i << ") at:\n";
      follows[a][i]->print(*_dout);
      *_dout << dendl;
      return true;
    }
  }

  return false;
}

int lockdep_will_lock(const char *name, int id)
{
  pthread_t p = pthread_self();
  if (id < 0) id = lockdep_register(name);

  pthread_mutex_lock(&lockdep_mutex);
  dout(20) << "_will_lock " << name << " (" << id << ")" << dendl;

  // check dependency graph
  map<int, BackTrace *> &m = held[p];
  for (map<int, BackTrace *>::iterator p = m.begin();
       p != m.end();
       p++) {
    if (p->first == id) {
      dout(0) << "\n";
      *_dout << "recursive lock of " << name << " (" << id << ")\n";
      BackTrace *bt = new BackTrace(BACKTRACE_SKIP);
      bt->print(*_dout);
      if (p->second) {
	*_dout << "\npreviously locked at\n";
	p->second->print(*_dout);
      }
      *_dout << dendl;
      assert(0);
    }
    else if (!follows[p->first][id]) {
      // new dependency

      // did we just create a cycle?
      BackTrace *bt = new BackTrace(BACKTRACE_SKIP);
      if (does_follow(id, p->first)) {
	dout(0) << "new dependency " << lock_names[p->first]
		<< " (" << p->first << ") -> " << name << " (" << id << ")"
		<< " creates a cycle at\n";
	bt->print(*_dout);
	*_dout << dendl;

	dout(0) << "btw, i am holding these locks:" << dendl;
	for (map<int, BackTrace *>::iterator q = m.begin();
	     q != m.end();
	     q++) {
	  dout(0) << "  " << lock_names[q->first] << " (" << q->first << ")" << dendl;
	  if (q->second) {
	    dout(0) << " ";
	    q->second->print(*_dout);
	    *_dout << dendl;
	  }
	}

	dout(0) << "\n" << dendl;

	// don't add this dependency, or we'll get aMutex. cycle in the graph, and
	// does_follow() won't terminate.

	assert(0);  // actually, we should just die here.
      } else {
	follows[p->first][id] = bt;
	dout(10) << lock_names[p->first] << " -> " << name << " at" << dendl;
	//bt->print(*_dout);
      }
    }
  }

  pthread_mutex_unlock(&lockdep_mutex);
  return id;
}

int lockdep_locked(const char *name, int id, bool force_backtrace)
{
  pthread_t p = pthread_self();

  if (id < 0) id = lockdep_register(name);

  pthread_mutex_lock(&lockdep_mutex);
  dout(20) << "_locked " << name << dendl;
  if (g_lockdep >= 2 || force_backtrace)
    held[p][id] = new BackTrace(BACKTRACE_SKIP);
  else
    held[p][id] = 0;
  pthread_mutex_unlock(&lockdep_mutex);
  return id;
}

int lockdep_will_unlock(const char *name, int id)
{
  pthread_t p = pthread_self();

  if (id < 0) {
    //id = lockdep_register(name);
    assert(id == -1);
    return id;
  }

  pthread_mutex_lock(&lockdep_mutex);
  dout(20) << "_will_unlock " << name << dendl;

  // don't assert.. lockdep may be enabled at any point in time
  //assert(held.count(p));
  //assert(held[p].count(id));

  delete held[p][id];
  held[p].erase(id);
  pthread_mutex_unlock(&lockdep_mutex);
  return id;
}

<|endoftext|>


<commit_before>#include <boost/algorithm/string.hpp>

#include "fish_annotator/common/species.h"

namespace fish_annotator {

Species::Species(const std::string& name)
  : name_()
  , subspecies_() {
  std::string lower_name = name;
  boost::algorithm::to_lower(lower_name);
  name_ = lower_name;
}

Species::Species()
  : name_()
  , subspecies_() {
}

std::vector<std::string> &Species::getSubspecies() {
  return subspecies_;
}

const std::vector<std::string> &Species::getSubspecies() const {
  return subspecies_;
}

bool Species::operator==(Species &rhs) {
  if(name_ != rhs.name_) return false;
  if(subspecies_.size() != rhs.subspecies_.size()) return false;
  for(uint32_t n=0; n < subspecies_.size(); n++) {
    if(subspecies_[n] != rhs.subspecies_[n]) return false;
  }
  return true;
}

bool Species::operator!=(Species &rhs) {
  return !operator==(rhs);
}

pt::ptree Species::write() const {
  pt::ptree tree;
  tree.put("name", name_);
  for(const auto &subname : subspecies_) {
    tree.add("subspecies_list.subspecies", subname);
  }
  return tree;
}

void Species::read(const pt::ptree &tree) {
  name_ = tree.get<std::string>("name");
  if(tree.count("subspecies_list") > 0) {
    for(auto &val : tree.get_child("subspecies_list")) {
      subspecies_.push_back(val.second.data());
    }
  }
}

SpeciesList::SpeciesList()
  : species_() {
}

std::vector<Species> &SpeciesList::getSpecies() {
  return species_;
}

bool SpeciesList::operator==(SpeciesList &rhs) {
  if(species_.size() != rhs.species_.size()) return false;
  for(uint32_t n=0; n < species_.size(); n++) {
    if(species_[n] != rhs.species_[n]) return false;
  }
  return true;
}

bool SpeciesList::operator!=(SpeciesList &rhs) {
  return !operator==(rhs);
}

pt::ptree SpeciesList::write() const {
  pt::ptree tree;
  for(const auto &species : species_) {
    tree.add_child("species_list.species", species.write());
  }
  return tree;
}

void SpeciesList::read(const pt::ptree &tree) {
  for(auto &val : tree.get_child("species_list")) {
    Species species;
    species.read(val.second);
    species_.push_back(species);
  }
}

} // namespace fish_annotator
<commit_msg>Make species lowercase when loading from file<commit_after>#include <boost/algorithm/string.hpp>

#include "fish_annotator/common/species.h"

namespace fish_annotator {

Species::Species(const std::string& name)
  : name_(name)
  , subspecies_() {
  boost::algorithm::to_lower(name_);
}

Species::Species()
  : name_()
  , subspecies_() {
}

std::vector<std::string> &Species::getSubspecies() {
  return subspecies_;
}

const std::vector<std::string> &Species::getSubspecies() const {
  return subspecies_;
}

bool Species::operator==(Species &rhs) {
  if(name_ != rhs.name_) return false;
  if(subspecies_.size() != rhs.subspecies_.size()) return false;
  for(uint32_t n=0; n < subspecies_.size(); n++) {
    if(subspecies_[n] != rhs.subspecies_[n]) return false;
  }
  return true;
}

bool Species::operator!=(Species &rhs) {
  return !operator==(rhs);
}

pt::ptree Species::write() const {
  pt::ptree tree;
  tree.put("name", name_);
  for(const auto &subname : subspecies_) {
    tree.add("subspecies_list.subspecies", subname);
  }
  return tree;
}

void Species::read(const pt::ptree &tree) {
  name_ = tree.get<std::string>("name");
  boost::algorithm::to_lower(name_);
  if(tree.count("subspecies_list") > 0) {
    for(auto &val : tree.get_child("subspecies_list")) {
      subspecies_.push_back(val.second.data());
    }
  }
}

SpeciesList::SpeciesList()
  : species_() {
}

std::vector<Species> &SpeciesList::getSpecies() {
  return species_;
}

bool SpeciesList::operator==(SpeciesList &rhs) {
  if(species_.size() != rhs.species_.size()) return false;
  for(uint32_t n=0; n < species_.size(); n++) {
    if(species_[n] != rhs.species_[n]) return false;
  }
  return true;
}

bool SpeciesList::operator!=(SpeciesList &rhs) {
  return !operator==(rhs);
}

pt::ptree SpeciesList::write() const {
  pt::ptree tree;
  for(const auto &species : species_) {
    tree.add_child("species_list.species", species.write());
  }
  return tree;
}

void SpeciesList::read(const pt::ptree &tree) {
  for(auto &val : tree.get_child("species_list")) {
    Species species;
    species.read(val.second);
    species_.push_back(species);
  }
}

} // namespace fish_annotator
<|endoftext|>


<commit_before>/*
 Copyright (c) 2014 Anon authors, see AUTHORS file.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/

#include "tls_fiber.h"

#define OPENSSL_THREAD_DEFINES
#include <openssl/opensslconf.h>
#if defined(OPENSSL_THREADS)
   // ok, this is what we want
#else
   #error SSL thread support disabled, cannot build
#endif

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/x509v3.h>

#include <vector>

static std::vector<fiber_mutex>  mutex_buff(CRYPTO_num_locks());

static void locking_func(int mode,int n, const char *file,int line)
{
  //anon_log("ssl " << (mode & CRYPTO_LOCK ? "locking" : "unlocking") << " \"" << file << "\":" << line << ", with n = " << n);
  if (mode & CRYPTO_LOCK)
    mutex_buff[n].lock();
  else
    mutex_buff[n].unlock();
}

static unsigned long id_func(void)
{
  //anon_log("id_func returning " << get_current_fiber());
  return (unsigned long)get_current_fiber();
}

tls_fiber_init::tls_fiber_init()
{
  (void)SSL_library_init();
  SSL_load_error_strings();
  RAND_load_file("/dev/urandom", 1024);

  CRYPTO_set_locking_callback(locking_func);
  CRYPTO_set_id_callback(id_func);
}

tls_fiber_init::~tls_fiber_init()
{
  ERR_free_strings();
}

////////////////////////////////////////////////////////////////////

#define BIO_TYPE_FIBER_PIPE	(53|0x0400|0x0100)	/* '53' is our custom type, 4, and 1 are BIO_TYPE_SOURCE_SINK and BIO_TYPE_DESCRIPTOR */

static int fp_write(BIO *h, const char *buf, int num);
static int fp_read(BIO *h, char *buf, int size);
static int fp_puts(BIO *h, const char *str);
static int fp_gets(BIO *h, char *buf, int size);
static long fp_ctrl(BIO *h, int cmd, long arg1, void *arg2);
static int fp_new(BIO *h);
static int fp_free(BIO *data);

static BIO_METHOD methods_fdp =
{
  BIO_TYPE_FIBER_PIPE,"fiber_pipe",
  fp_write,
  fp_read,
  fp_puts,
  fp_gets,
  fp_ctrl,
  fp_new,
  fp_free,
  NULL,
};

static BIO *BIO_new_fp(std::unique_ptr<fiber_pipe>&& pipe)
{
  BIO *b = BIO_new(&methods_fdp);
  if (b == 0)
    return 0;
  b->ptr = new std::unique_ptr<fiber_pipe>(std::move(pipe));
  return b;
}

static int fp_new(BIO *b)
{
  b->init = 1;
  b->ptr=NULL;
  return 1;
}

static int fp_free(BIO *b)
{
  if (b == NULL)
    return 0;
  auto p = reinterpret_cast<std::unique_ptr<fiber_pipe>*>(b->ptr);
  if (p)
    delete p;
  b->ptr = 0;
  return 1;
}

static int fp_read(BIO *b, char *out, int outl)
{
  auto p = reinterpret_cast<std::unique_ptr<fiber_pipe>*>(b->ptr);
  if (p)
    return (*p)->read(out, outl);
  return -1;
}

static int fp_write(BIO *b, const char *in, int inl)
{
  auto p = reinterpret_cast<std::unique_ptr<fiber_pipe>*>(b->ptr);
  if (p) {
    (*p)->write(in, inl);
    return inl;
  }
  return -1;
}

static long fp_ctrl(BIO *b, int cmd, long num, void *ptr)
{
  long ret=1;

  switch (cmd) {
    case BIO_CTRL_RESET:
      anon_log("fp_ctrl BIO_CTRL_RESET");
      break;
    case BIO_CTRL_EOF:
      anon_log("fp_ctrl BIO_CTRL_EOF");
      break;
    case BIO_CTRL_INFO:
      anon_log("fp_ctrl BIO_CTRL_INFO");
      break;
    case BIO_CTRL_SET:
      anon_log("fp_ctrl BIO_CTRL_SET");
      break;
    case BIO_CTRL_GET:
      anon_log("fp_ctrl BIO_CTRL_GET");
      break;
    case BIO_CTRL_PUSH:
      anon_log("fp_ctrl BIO_CTRL_PUSH");
      break;
    case BIO_CTRL_POP:
      anon_log("fp_ctrl BIO_CTRL_POP");
      break;
    case BIO_CTRL_GET_CLOSE:
      anon_log("fp_ctrl BIO_CTRL_GET_CLOSE");
      break;
    case BIO_CTRL_SET_CLOSE:
      anon_log("fp_ctrl BIO_CTRL_SET_CLOSE");
      break;
    case BIO_CTRL_PENDING:
      anon_log("fp_ctrl BIO_CTRL_PENDING");
      ret = 0;
      break;
    case BIO_CTRL_FLUSH:
      anon_log("fp_ctrl BIO_CTRL_FLUSH");
      break;
    case BIO_CTRL_DUP:
      anon_log("fp_ctrl BIO_CTRL_DUP");
      break;
    default:
      anon_log("fp_ctrl unknown: " << cmd);
      ret=0;
      break;
  }
  return ret;
}

static int fp_puts(BIO *b, const char *str)
{
  return fp_write(b, str, strlen(str));
}

static int fp_gets(BIO *b, char *buf, int size)
{
  int ret=0;
  char *ptr=buf;
  char *end=buf+size-1;

  while ((ptr < end) && (fp_read(b, ptr, 1) > 0) && (ptr[0] != '\n'))
    ptr++;

  ptr[0] = 0;
  return strlen(buf);
}

////////////////////////////////////////////////////////////////////

static void throw_ssl_error(unsigned long err)
{
  const char* er = ERR_reason_error_string(err);
  if (er)
    throw std::runtime_error(er);
  throw std::runtime_error("unknown openssl error");
}

static void throw_ssl_error()
{
  throw_ssl_error(ERR_get_error());
}

static void print_cn_name(const char* label, X509_NAME* const name)
{
  int idx = -1, success = 0;
  unsigned char *utf8 = NULL;

  do
  {
    if(!name) break; /* failed */

    idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
    if(!(idx > -1))  break; /* failed */

    X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, idx);
    if(!entry) break; /* failed */

    ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry);
    if(!data) break; /* failed */

    int length = ASN1_STRING_to_UTF8(&utf8, data);
    if(!utf8 || !(length > 0))  break; /* failed */

    anon_log(label << ": " << (char*)utf8);

    success = 1;

  } while (0);

  if(utf8)
    OPENSSL_free(utf8);

  if(!success)
    anon_log(label << ": <not available>");
}

void print_san_name(const char* label, X509* const cert)
{
  int success = 0;
  GENERAL_NAMES* names = NULL;
  unsigned char* utf8 = NULL;

  do
  {
    if(!cert) break; /* failed */

    names = (GENERAL_NAMES*)X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
    if(!names) break;

    int i = 0, count = sk_GENERAL_NAME_num(names);
    if(!count) break; /* failed */

    for( i = 0; i < count; ++i ) {
      GENERAL_NAME* entry = sk_GENERAL_NAME_value(names, i);
      if(!entry) continue;

      if(GEN_DNS == entry->type) {
        int len1 = 0, len2 = -1;

        len1 = ASN1_STRING_to_UTF8(&utf8, entry->d.dNSName);
        if(utf8)
          len2 = (int)strlen((const char*)utf8);

        if(len1 != len2)
          anon_log("Strlen and ASN1_STRING size do not match (embedded null?): " << len2 << " vs " << len1);

        /* If there's a problem with string lengths, then     */
        /* we skip the candidate and move on to the next.     */
        /* Another policy would be to fails since it probably */
        /* indicates the client is under attack.              */
        if(utf8 && len1 && len2 && (len1 == len2)) {
          anon_log(label << ": " << utf8);
          success = 1;
        }

        if(utf8)
          OPENSSL_free(utf8), utf8 = NULL;
      }
      else
        anon_log("Unknown GENERAL_NAME type: " << entry->type);
    }

  } while (0);

  if(names)
    GENERAL_NAMES_free(names);

  if(utf8)
    OPENSSL_free(utf8);

  if(!success)
    anon_log(label << ": not available");
}

static int verify_callback(int preverify, X509_STORE_CTX* x509_ctx)
{
  /* For error codes, see http://www.openssl.org/docs/apps/verify.html  */

  int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
  int err = X509_STORE_CTX_get_error(x509_ctx);

  X509* cert = X509_STORE_CTX_get_current_cert(x509_ctx);
  X509_NAME* iname = cert ? X509_get_issuer_name(cert) : NULL;
  X509_NAME* sname = cert ? X509_get_subject_name(cert) : NULL;

  anon_log("ssl verify_callback depth: " << depth << ", preverify: " << preverify);

  /* Issuer is the authority we trust that warrants nothing useful */
  print_cn_name("Issuer (cn)", iname);

  /* Subject is who the certificate is issued to by the authority  */
  print_cn_name("Subject (cn)", sname);

  if(depth == 0) {
    /* If depth is 0, its the server's certificate. Print the SANs */
    print_san_name("Subject (san)", cert);
  }

  if(preverify == 0)
  {
    if(err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
      anon_log("Error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY");
    else if(err == X509_V_ERR_CERT_UNTRUSTED)
      anon_log("Error = X509_V_ERR_CERT_UNTRUSTED");
    else if(err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)
      anon_log("Error = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN");
    else if(err == X509_V_ERR_CERT_NOT_YET_VALID)
      anon_log("Error = X509_V_ERR_CERT_NOT_YET_VALID");
    else if(err == X509_V_ERR_CERT_HAS_EXPIRED)
      anon_log("Error = X509_V_ERR_CERT_HAS_EXPIRED");
    else if(err == X509_V_OK)
      anon_log("Error = X509_V_OK\n");
    else
      anon_log("Error = " << err);
  }

  #if defined(IGNORE_ERRORS)
  return 1;
  #else
  return preverify;
  #endif
}

tls_pipe::tls_pipe(std::unique_ptr<fiber_pipe>&& pipe, bool client/*vs. server*/, const char* host_name)
{
  ctx_ = SSL_CTX_new(client ? SSLv23_client_method() : SSLv23_server_method());
  if (ctx_ == 0)
    throw_ssl_error();
  SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER, verify_callback);
  SSL_CTX_set_verify_depth(ctx_, 5);

  const long flags = SSL_OP_ALL /*| SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3*/ | SSL_OP_NO_COMPRESSION;
  (void)SSL_CTX_set_options(ctx_, flags);

  if (SSL_CTX_use_certificate_file(ctx_,"verisign.pem",SSL_FILETYPE_PEM)==0) {
    auto ec = ERR_get_error();
    SSL_CTX_free(ctx_);
    throw_ssl_error(ec);
  }

  if (false && SSL_CTX_load_verify_locations(ctx_, "verisign.pem", 0) == 0) {
    auto ec = ERR_get_error();
    SSL_CTX_free(ctx_);
    throw_ssl_error(ec);
  }

  BIO* fpb = BIO_new_fp(std::move(pipe));
  if (!fpb) {
    auto ec = ERR_get_error();
    SSL_CTX_free(ctx_);
    throw_ssl_error(ec);
  }
  ssl_ = BIO_new_ssl(ctx_,client);
  if (!ssl_) {
    auto ec = ERR_get_error();
    BIO_free(fpb);
    SSL_CTX_free(ctx_);
    throw_ssl_error(ec);
  }
  BIO_push(ssl_,fpb);

  if (BIO_do_handshake(ssl_) != 1) {
    auto ec = ERR_get_error();
    BIO_free(ssl_);
    SSL_CTX_free(ctx_);
    throw_ssl_error(ec);
  }

  SSL *ssl = 0;
  BIO_get_ssl(ssl_, &ssl);

  if (client) {

    /* Step 1: verify a server certifcate was presented during negotiation
              Anonymous Diffie-Hellman (ADH) is not allowed
    */
    X509* cert = SSL_get_peer_certificate(ssl);
    if(cert)
      X509_free(cert); /* Free immediately */
    else {
      BIO_free(ssl_);
      SSL_CTX_free(ctx_);
      throw_ssl_error(X509_V_ERR_APPLICATION_VERIFICATION);
    }

    auto res = SSL_get_verify_result(ssl);
    if (res != X509_V_OK) {
      BIO_free(ssl_);
      SSL_CTX_free(ctx_);
      throw_ssl_error((unsigned long)res);
    }

    // check host_name

  }

}

<commit_msg>ssl tweaks<commit_after>/*
 Copyright (c) 2014 Anon authors, see AUTHORS file.

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/

#include "tls_fiber.h"

#define OPENSSL_THREAD_DEFINES
#include <openssl/opensslconf.h>
#if defined(OPENSSL_THREADS)
   // ok, this is what we want
#else
   #error SSL thread support disabled, cannot build
#endif

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/x509v3.h>

#include <vector>

static std::vector<fiber_mutex>  mutex_buff(CRYPTO_num_locks());

static void locking_func(int mode,int n, const char *file,int line)
{
  //anon_log("ssl " << (mode & CRYPTO_LOCK ? "locking" : "unlocking") << " \"" << file << "\":" << line << ", with n = " << n);
  if (mode & CRYPTO_LOCK)
    mutex_buff[n].lock();
  else
    mutex_buff[n].unlock();
}

static unsigned long id_func(void)
{
  //anon_log("id_func returning " << get_current_fiber());
  return (unsigned long)get_current_fiber();
}

tls_fiber_init::tls_fiber_init()
{
  (void)SSL_library_init();
  SSL_load_error_strings();
  RAND_load_file("/dev/urandom", 1024);

  CRYPTO_set_locking_callback(locking_func);
  //CRYPTO_set_id_callback(id_func);
}

tls_fiber_init::~tls_fiber_init()
{
  ERR_free_strings();
}

////////////////////////////////////////////////////////////////////

#define BIO_TYPE_FIBER_PIPE	(53|0x0400|0x0100)	/* '53' is our custom type, 4, and 1 are BIO_TYPE_SOURCE_SINK and BIO_TYPE_DESCRIPTOR */

static int fp_write(BIO *h, const char *buf, int num);
static int fp_read(BIO *h, char *buf, int size);
static int fp_puts(BIO *h, const char *str);
static int fp_gets(BIO *h, char *buf, int size);
static long fp_ctrl(BIO *h, int cmd, long arg1, void *arg2);
static int fp_new(BIO *h);
static int fp_free(BIO *data);

static BIO_METHOD methods_fdp =
{
  BIO_TYPE_FIBER_PIPE,"fiber_pipe",
  fp_write,
  fp_read,
  fp_puts,
  fp_gets,
  fp_ctrl,
  fp_new,
  fp_free,
  NULL,
};

static BIO *BIO_new_fp(std::unique_ptr<fiber_pipe>&& pipe)
{
  BIO *b = BIO_new(&methods_fdp);
  if (b == 0)
    return 0;
  b->ptr = new std::unique_ptr<fiber_pipe>(std::move(pipe));
  return b;
}

static int fp_new(BIO *b)
{
  b->init = 1;
  b->ptr=NULL;
  return 1;
}

static int fp_free(BIO *b)
{
  if (b == NULL)
    return 0;
  auto p = reinterpret_cast<std::unique_ptr<fiber_pipe>*>(b->ptr);
  if (p)
    delete p;
  b->ptr = 0;
  return 1;
}

static int fp_read(BIO *b, char *out, int outl)
{
  auto p = reinterpret_cast<std::unique_ptr<fiber_pipe>*>(b->ptr);
  if (p)
    return (*p)->read(out, outl);
  return -1;
}

static int fp_write(BIO *b, const char *in, int inl)
{
  auto p = reinterpret_cast<std::unique_ptr<fiber_pipe>*>(b->ptr);
  if (p) {
    (*p)->write(in, inl);
    return inl;
  }
  return -1;
}

static long fp_ctrl(BIO *b, int cmd, long num, void *ptr)
{
  long ret=1;

  switch (cmd) {
    case BIO_CTRL_RESET:
      anon_log("fp_ctrl BIO_CTRL_RESET");
      break;
    case BIO_CTRL_EOF:
      anon_log("fp_ctrl BIO_CTRL_EOF");
      break;
    case BIO_CTRL_INFO:
      anon_log("fp_ctrl BIO_CTRL_INFO");
      break;
    case BIO_CTRL_SET:
      anon_log("fp_ctrl BIO_CTRL_SET");
      break;
    case BIO_CTRL_GET:
      anon_log("fp_ctrl BIO_CTRL_GET");
      break;
    case BIO_CTRL_PUSH:
      //anon_log("fp_ctrl BIO_CTRL_PUSH");
      break;
    case BIO_CTRL_POP:
      //anon_log("fp_ctrl BIO_CTRL_POP");
      break;
    case BIO_CTRL_GET_CLOSE:
      anon_log("fp_ctrl BIO_CTRL_GET_CLOSE");
      break;
    case BIO_CTRL_SET_CLOSE:
      anon_log("fp_ctrl BIO_CTRL_SET_CLOSE");
      break;
    case BIO_CTRL_PENDING:
      anon_log("fp_ctrl BIO_CTRL_PENDING");
      ret = 0;
      break;
    case BIO_CTRL_FLUSH:
      //anon_log("fp_ctrl BIO_CTRL_FLUSH");
      break;
    case BIO_CTRL_DUP:
      anon_log("fp_ctrl BIO_CTRL_DUP");
      break;
    default:
      anon_log("fp_ctrl unknown: " << cmd);
      ret=0;
      break;
  }
  return ret;
}

static int fp_puts(BIO *b, const char *str)
{
  return fp_write(b, str, strlen(str));
}

static int fp_gets(BIO *b, char *buf, int size)
{
  int ret=0;
  char *ptr=buf;
  char *end=buf+size-1;

  while ((ptr < end) && (fp_read(b, ptr, 1) > 0) && (ptr[0] != '\n'))
    ptr++;

  ptr[0] = 0;
  return strlen(buf);
}

////////////////////////////////////////////////////////////////////

static void throw_ssl_error(unsigned long err)
{
  const char* er = ERR_reason_error_string(err);
  if (er)
    throw std::runtime_error(er);
  throw std::runtime_error("unknown openssl error");
}

static void throw_ssl_error()
{
  throw_ssl_error(ERR_get_error());
}

//#define PRINT_CERT_INFO

#ifdef PRINT_CERT_INFO
static void print_cn_name(const char* label, X509_NAME* const name)
{
  int idx = -1, success = 0;
  unsigned char *utf8 = NULL;

  do
  {
    if(!name) break; /* failed */

    idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
    if(!(idx > -1))  break; /* failed */

    X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, idx);
    if(!entry) break; /* failed */

    ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry);
    if(!data) break; /* failed */

    int length = ASN1_STRING_to_UTF8(&utf8, data);
    if(!utf8 || !(length > 0))  break; /* failed */

    anon_log(label << ": " << (char*)utf8);

    success = 1;

  } while (0);

  if(utf8)
    OPENSSL_free(utf8);

  if(!success)
    anon_log(label << ": <not available>");
}

void print_san_name(const char* label, X509* const cert)
{
  int success = 0;
  GENERAL_NAMES* names = NULL;
  unsigned char* utf8 = NULL;

  do
  {
    if(!cert) break; /* failed */

    names = (GENERAL_NAMES*)X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
    if(!names) break;

    int i = 0, count = sk_GENERAL_NAME_num(names);
    if(!count) break; /* failed */

    for( i = 0; i < count; ++i ) {
      GENERAL_NAME* entry = sk_GENERAL_NAME_value(names, i);
      if(!entry) continue;

      if(GEN_DNS == entry->type) {
        int len1 = 0, len2 = -1;

        len1 = ASN1_STRING_to_UTF8(&utf8, entry->d.dNSName);
        if(utf8)
          len2 = (int)strlen((const char*)utf8);

        if(len1 != len2)
          anon_log("Strlen and ASN1_STRING size do not match (embedded null?): " << len2 << " vs " << len1);

        /* If there's a problem with string lengths, then     */
        /* we skip the candidate and move on to the next.     */
        /* Another policy would be to fails since it probably */
        /* indicates the client is under attack.              */
        if(utf8 && len1 && len2 && (len1 == len2)) {
          anon_log(label << ": " << utf8);
          success = 1;
        }

        if(utf8)
          OPENSSL_free(utf8), utf8 = NULL;
      }
      else
        anon_log("Unknown GENERAL_NAME type: " << entry->type);
    }

  } while (0);

  if(names)
    GENERAL_NAMES_free(names);

  if(utf8)
    OPENSSL_free(utf8);

  if(!success)
    anon_log(label << ": not available");
}
#endif

static int verify_callback(int preverify, X509_STORE_CTX* x509_ctx)
{
  /* For error codes, see http://www.openssl.org/docs/apps/verify.html  */

  int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
  int err = X509_STORE_CTX_get_error(x509_ctx);

  X509* cert = X509_STORE_CTX_get_current_cert(x509_ctx);
  X509_NAME* iname = cert ? X509_get_issuer_name(cert) : NULL;
  X509_NAME* sname = cert ? X509_get_subject_name(cert) : NULL;

#ifdef PRINT_CERT_INFO
  anon_log("ssl verify_callback depth: " << depth << ", preverify: " << preverify);

  /* Issuer is the authority we trust that warrants nothing useful */
  print_cn_name("Issuer (cn)", iname);

  /* Subject is who the certificate is issued to by the authority  */
  print_cn_name("Subject (cn)", sname);

  if(depth == 0) {
    /* If depth is 0, its the server's certificate. Print the SANs */
    print_san_name("Subject (san)", cert);
  }

  if(preverify == 0)
  {
    if(err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
      anon_log("Error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY");
    else if(err == X509_V_ERR_CERT_UNTRUSTED)
      anon_log("Error = X509_V_ERR_CERT_UNTRUSTED");
    else if(err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)
      anon_log("Error = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN");
    else if(err == X509_V_ERR_CERT_NOT_YET_VALID)
      anon_log("Error = X509_V_ERR_CERT_NOT_YET_VALID");
    else if(err == X509_V_ERR_CERT_HAS_EXPIRED)
      anon_log("Error = X509_V_ERR_CERT_HAS_EXPIRED");
    else if(err == X509_V_OK)
      anon_log("Error = X509_V_OK\n");
    else
      anon_log("Error = " << err);
  }
#endif

  #if defined(IGNORE_ERRORS)
  return 1;
  #else
  return preverify;
  #endif
}

tls_pipe::tls_pipe(std::unique_ptr<fiber_pipe>&& pipe, bool client/*vs. server*/, const char* host_name)
{
  ctx_ = SSL_CTX_new(client ? SSLv23_client_method() : SSLv23_server_method());
  if (ctx_ == 0)
    throw_ssl_error();
  SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
  SSL_CTX_set_verify_depth(ctx_, 5);

  const long flags = SSL_OP_ALL /*| SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3*/ | SSL_OP_NO_COMPRESSION;
  (void)SSL_CTX_set_options(ctx_, flags);

  if (SSL_CTX_load_verify_locations(ctx_, 0, "/etc/ssl/certs") == 0) {
    auto ec = ERR_get_error();
    SSL_CTX_free(ctx_);
    throw_ssl_error(ec);
  }

  BIO* fpb = BIO_new_fp(std::move(pipe));
  if (!fpb) {
    auto ec = ERR_get_error();
    SSL_CTX_free(ctx_);
    throw_ssl_error(ec);
  }
  ssl_ = BIO_new_ssl(ctx_,client);
  if (!ssl_) {
    auto ec = ERR_get_error();
    BIO_free(fpb);
    SSL_CTX_free(ctx_);
    throw_ssl_error(ec);
  }
  BIO_push(ssl_,fpb);

  if (BIO_do_handshake(ssl_) != 1) {
    anon_log("BIO_do_handshake returned error");
    auto ec = ERR_get_error();
    anon_log("ERR_get_error returned: " << ec);
    BIO_free(ssl_);
    SSL_CTX_free(ctx_);
    throw_ssl_error(ec);
  }

  SSL *ssl = 0;
  BIO_get_ssl(ssl_, &ssl);

  if (client) {

    /* Step 1: verify a server certifcate was presented during negotiation
              Anonymous Diffie-Hellman (ADH) is not allowed
    */
    X509* cert = SSL_get_peer_certificate(ssl);
    if(cert)
      X509_free(cert); /* Free immediately */
    else {
      BIO_free(ssl_);
      SSL_CTX_free(ctx_);
      throw_ssl_error(X509_V_ERR_APPLICATION_VERIFICATION);
    }

    auto res = SSL_get_verify_result(ssl);
    if (res != X509_V_OK) {
      anon_log("SSL_get_verify_result returned error: " << res);
      BIO_free(ssl_);
      SSL_CTX_free(ctx_);
      throw_ssl_error((unsigned long)res);
    }

    // check host_name

    anon_log("handshake completed, certificates accepted, ready to communicate");

  }

}

<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "disk_interface.h"

#include <algorithm>

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifdef _WIN32
#include <windows.h>
#include <direct.h>  // _mkdir
#endif

#include "util.h"

namespace {

string DirName(const string& path) {
#ifdef _WIN32
  const char kPathSeparators[] = "\\/";
#else
  const char kPathSeparators[] = "/";
#endif
  string::size_type slash_pos = path.find_last_of(kPathSeparators);
  if (slash_pos == string::npos)
    return string();  // Nothing to do.
  const char* const kEnd = kPathSeparators + strlen(kPathSeparators);
  while (slash_pos > 0 &&
         std::find(kPathSeparators, kEnd, path[slash_pos - 1]) != kEnd)
    --slash_pos;
  return path.substr(0, slash_pos);
}

int MakeDir(const string& path) {
#ifdef _WIN32
  return _mkdir(path.c_str());
#else
  return mkdir(path.c_str(), 0777);
#endif
}

TimeStamp TimeStampFromFileTime(const FILETIME& filetime) {
  // FILETIME is in 100-nanosecond increments since the Windows epoch.
  // We don't much care about epoch correctness but we do want the
  // resulting value to fit in an integer.
  uint64_t mtime = ((uint64_t)filetime.dwHighDateTime << 32) |
    ((uint64_t)filetime.dwLowDateTime);
  mtime /= 1000000000LL / 100; // 100ns -> s.
  mtime -= 12622770400LL;  // 1600 epoch -> 2000 epoch (subtract 400 years).
  return (TimeStamp)mtime;
}

TimeStamp StatSingleFile(const string& path, bool quiet) {
  WIN32_FILE_ATTRIBUTE_DATA attrs;
  if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &attrs)) {
    DWORD err = GetLastError();
    if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
      return 0;
    if (!quiet) {
      Error("GetFileAttributesEx(%s): %s", path.c_str(),
            GetLastErrorString().c_str());
    }
    return -1;
  }
  return TimeStampFromFileTime(attrs.ftLastWriteTime);
}

void StatAllFilesInDir(const string& dir, map<string, TimeStamp>* stamps) {
  HANDLE hFind = INVALID_HANDLE_VALUE;
  WIN32_FIND_DATAA ffd;

  // FindExInfoBasic is 30% faster than FindExInfoStandard.
  hFind = FindFirstFileExA((dir + "\\*").c_str(), FindExInfoBasic, &ffd,
                           FindExSearchNameMatch, NULL, 0);

  if (hFind == INVALID_HANDLE_VALUE) {
    fprintf(stderr, "fail %s", dir.c_str());
    exit(-1);
  }
  do {
    if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
      continue;

    string lowername = ffd.cFileName;
    transform(lowername.begin(), lowername.end(), lowername.begin(), ::tolower);

    const FILETIME& filetime = ffd.ftLastWriteTime;
    (*stamps).insert(make_pair(lowername, TimeStampFromFileTime(filetime)));
  } while (FindNextFileA(hFind, &ffd));
  FindClose(hFind);
}

}  // namespace

// DiskInterface ---------------------------------------------------------------

bool DiskInterface::MakeDirs(const string& path) {
  string dir = DirName(path);
  if (dir.empty())
    return true;  // Reached root; assume it's there.
  TimeStamp mtime = Stat(dir);
  if (mtime < 0)
    return false;  // Error.
  if (mtime > 0)
    return true;  // Exists already; we're done.

  // Directory doesn't exist.  Try creating its parent first.
  bool success = MakeDirs(dir);
  if (!success)
    return false;
  return MakeDir(dir);
}

// RealDiskInterface -----------------------------------------------------------

TimeStamp RealDiskInterface::Stat(const string& path) {
#ifdef _WIN32
  // MSDN: "Naming Files, Paths, and Namespaces"
  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
  if (!path.empty() && path[0] != '\\' && path.size() > MAX_PATH) {
    if (!quiet_) {
      Error("Stat(%s): Filename longer than %i characters",
            path.c_str(), MAX_PATH);
    }
    return -1;
  }
  if (!use_cache_)
    return StatSingleFile(path, quiet_);

  string dir = DirName(path);
  int offs = dir.size();
  if (offs) ++offs;  // skip \ too
  string base(path.substr(offs));

  transform(dir.begin(), dir.end(), dir.begin(), ::tolower);
  transform(base.begin(), base.end(), base.begin(), ::tolower);

  Cache::iterator ci = cache_.find(dir);
  if (ci != cache_.end()) {
    DirCache::iterator di = ci->second->find(base);
    if (di != ci->second->end())
      return di->second;
    return 0;
  }

  if (dir.empty())
    dir = ".";
  DirCache* dc = new DirCache;
  StatAllFilesInDir(dir, dc);

  if (dir == ".")
    cache_.insert(make_pair("", dc));
  else
    cache_.insert(make_pair(dir, dc));

  DirCache::iterator di = dc->find(base);
  if (di != dc->end())
    return di->second;
  return 0;

#else
  struct stat st;
  if (stat(path.c_str(), &st) < 0) {
    if (errno == ENOENT || errno == ENOTDIR)
      return 0;
    if (!quiet_) {
      Error("stat(%s): %s", path.c_str(), strerror(errno));
    }
    return -1;
  }
  return st.st_mtime;
#endif
}

bool RealDiskInterface::WriteFile(const string& path, const string& contents) {
  FILE* fp = fopen(path.c_str(), "w");
  if (fp == NULL) {
    Error("WriteFile(%s): Unable to create file. %s",
          path.c_str(), strerror(errno));
    return false;
  }

  if (fwrite(contents.data(), 1, contents.length(), fp) < contents.length())  {
    Error("WriteFile(%s): Unable to write to the file. %s",
          path.c_str(), strerror(errno));
    fclose(fp);
    return false;
  }

  if (fclose(fp) == EOF) {
    Error("WriteFile(%s): Unable to close the file. %s",
          path.c_str(), strerror(errno));
    return false;
  }

  return true;
}

bool RealDiskInterface::MakeDir(const string& path) {
  if (::MakeDir(path) < 0) {
    if (errno == EEXIST) {
      return true;
    }
    Error("mkdir(%s): %s", path.c_str(), strerror(errno));
    return false;
  }
  return true;
}

string RealDiskInterface::ReadFile(const string& path, string* err) {
  string contents;
  int ret = ::ReadFile(path, &contents, err);
  if (ret == -ENOENT) {
    // Swallow ENOENT.
    err->clear();
  }
  return contents;
}

int RealDiskInterface::RemoveFile(const string& path) {
  if (remove(path.c_str()) < 0) {
    switch (errno) {
      case ENOENT:
        return 1;
      default:
        Error("remove(%s): %s", path.c_str(), strerror(errno));
        return -1;
    }
  } else {
    return 0;
  }
}
<commit_msg>more minor cleanups<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "disk_interface.h"

#include <algorithm>

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifdef _WIN32
#include <windows.h>
#include <direct.h>  // _mkdir
#endif

#include "util.h"

namespace {

string DirName(const string& path) {
#ifdef _WIN32
  const char kPathSeparators[] = "\\/";
#else
  const char kPathSeparators[] = "/";
#endif
  string::size_type slash_pos = path.find_last_of(kPathSeparators);
  if (slash_pos == string::npos)
    return string();  // Nothing to do.
  const char* const kEnd = kPathSeparators + strlen(kPathSeparators);
  while (slash_pos > 0 &&
         std::find(kPathSeparators, kEnd, path[slash_pos - 1]) != kEnd)
    --slash_pos;
  return path.substr(0, slash_pos);
}

int MakeDir(const string& path) {
#ifdef _WIN32
  return _mkdir(path.c_str());
#else
  return mkdir(path.c_str(), 0777);
#endif
}

TimeStamp TimeStampFromFileTime(const FILETIME& filetime) {
  // FILETIME is in 100-nanosecond increments since the Windows epoch.
  // We don't much care about epoch correctness but we do want the
  // resulting value to fit in an integer.
  uint64_t mtime = ((uint64_t)filetime.dwHighDateTime << 32) |
    ((uint64_t)filetime.dwLowDateTime);
  mtime /= 1000000000LL / 100; // 100ns -> s.
  mtime -= 12622770400LL;  // 1600 epoch -> 2000 epoch (subtract 400 years).
  return (TimeStamp)mtime;
}

TimeStamp StatSingleFile(const string& path, bool quiet) {
  WIN32_FILE_ATTRIBUTE_DATA attrs;
  if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &attrs)) {
    DWORD err = GetLastError();
    if (err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
      return 0;
    if (!quiet) {
      Error("GetFileAttributesEx(%s): %s", path.c_str(),
            GetLastErrorString().c_str());
    }
    return -1;
  }
  return TimeStampFromFileTime(attrs.ftLastWriteTime);
}

void StatAllFilesInDir(const string& dir, map<string, TimeStamp>* stamps) {
  // FindExInfoBasic is 30% faster than FindExInfoStandard.
  WIN32_FIND_DATAA ffd;
  HANDLE hFind = FindFirstFileExA((dir + "\\*").c_str(), FindExInfoBasic, &ffd,
                                  FindExSearchNameMatch, NULL, 0);

  if (hFind == INVALID_HANDLE_VALUE) {
    fprintf(stderr, "fail %s", dir.c_str());
    exit(-1);
  }
  do {
    if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
      continue;

    string lowername = ffd.cFileName;
    transform(lowername.begin(), lowername.end(), lowername.begin(), ::tolower);

    const FILETIME& filetime = ffd.ftLastWriteTime;
    (*stamps).insert(make_pair(lowername, TimeStampFromFileTime(filetime)));
  } while (FindNextFileA(hFind, &ffd));
  FindClose(hFind);
}

}  // namespace

// DiskInterface ---------------------------------------------------------------

bool DiskInterface::MakeDirs(const string& path) {
  string dir = DirName(path);
  if (dir.empty())
    return true;  // Reached root; assume it's there.
  TimeStamp mtime = Stat(dir);
  if (mtime < 0)
    return false;  // Error.
  if (mtime > 0)
    return true;  // Exists already; we're done.

  // Directory doesn't exist.  Try creating its parent first.
  bool success = MakeDirs(dir);
  if (!success)
    return false;
  return MakeDir(dir);
}

// RealDiskInterface -----------------------------------------------------------

TimeStamp RealDiskInterface::Stat(const string& path) {
#ifdef _WIN32
  // MSDN: "Naming Files, Paths, and Namespaces"
  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
  if (!path.empty() && path[0] != '\\' && path.size() > MAX_PATH) {
    if (!quiet_) {
      Error("Stat(%s): Filename longer than %i characters",
            path.c_str(), MAX_PATH);
    }
    return -1;
  }
  if (!use_cache_)
    return StatSingleFile(path, quiet_);

  string dir = DirName(path);
  int offs = dir.size();
  if (offs) ++offs;  // skip \ too
  string base(path.substr(offs));

  transform(dir.begin(), dir.end(), dir.begin(), ::tolower);
  transform(base.begin(), base.end(), base.begin(), ::tolower);

  Cache::iterator ci = cache_.find(dir);
  if (ci != cache_.end()) {
    DirCache::iterator di = ci->second->find(base);
    return di != ci->second->end() ? di->second : 0;
  }

  DirCache* dc = new DirCache;
  StatAllFilesInDir(dir.empty() ? "." : dir, dc);
  cache_.insert(make_pair(dir, dc));

  DirCache::iterator di = dc->find(base);
  return di != dc->end() ? di->second : 0;
#else
  struct stat st;
  if (stat(path.c_str(), &st) < 0) {
    if (errno == ENOENT || errno == ENOTDIR)
      return 0;
    if (!quiet_) {
      Error("stat(%s): %s", path.c_str(), strerror(errno));
    }
    return -1;
  }
  return st.st_mtime;
#endif
}

bool RealDiskInterface::WriteFile(const string& path, const string& contents) {
  FILE* fp = fopen(path.c_str(), "w");
  if (fp == NULL) {
    Error("WriteFile(%s): Unable to create file. %s",
          path.c_str(), strerror(errno));
    return false;
  }

  if (fwrite(contents.data(), 1, contents.length(), fp) < contents.length())  {
    Error("WriteFile(%s): Unable to write to the file. %s",
          path.c_str(), strerror(errno));
    fclose(fp);
    return false;
  }

  if (fclose(fp) == EOF) {
    Error("WriteFile(%s): Unable to close the file. %s",
          path.c_str(), strerror(errno));
    return false;
  }

  return true;
}

bool RealDiskInterface::MakeDir(const string& path) {
  if (::MakeDir(path) < 0) {
    if (errno == EEXIST) {
      return true;
    }
    Error("mkdir(%s): %s", path.c_str(), strerror(errno));
    return false;
  }
  return true;
}

string RealDiskInterface::ReadFile(const string& path, string* err) {
  string contents;
  int ret = ::ReadFile(path, &contents, err);
  if (ret == -ENOENT) {
    // Swallow ENOENT.
    err->clear();
  }
  return contents;
}

int RealDiskInterface::RemoveFile(const string& path) {
  if (remove(path.c_str()) < 0) {
    switch (errno) {
      case ENOENT:
        return 1;
      default:
        Error("remove(%s): %s", path.c_str(), strerror(errno));
        return -1;
    }
  } else {
    return 0;
  }
}
<|endoftext|>