274 changed files with 35786 additions and 5097 deletions
@ -0,0 +1,103 @@ |
|||
/* BEGIN COPYRIGHT
|
|||
* |
|||
* This file is part of Noted. |
|||
* |
|||
* Copyright ©2011, 2012, Lancaster Logic Response Limited. |
|||
* |
|||
* Noted 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 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* Noted 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 Noted. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <algorithm> |
|||
#include <type_traits> |
|||
#include <cmath> |
|||
|
|||
#undef foreach |
|||
#define foreach BOOST_FOREACH |
|||
|
|||
namespace lb |
|||
{ |
|||
|
|||
template <class T> |
|||
static T graphParameters(T _min, T _max, unsigned _divisions, T* o_from = 0, T* o_delta = 0, bool _forceMinor = false, T _divisor = 1) |
|||
{ |
|||
T uMin = _min / _divisor; |
|||
T uMax = _max / _divisor; |
|||
if (uMax == uMin || !_divisions) |
|||
{ |
|||
*o_from = 0; |
|||
*o_delta = 1; |
|||
return 1; |
|||
} |
|||
long double l10 = std::log10((uMax - uMin) / T(_divisions) * 5.5f); |
|||
long double mt = std::pow(10.f, l10 - std::floor(l10)); |
|||
long double ep = std::pow(10.f, std::floor(l10)); |
|||
T inc = _forceMinor |
|||
? ((mt > 6.f) ? ep / 2.f : (mt > 3.f) ? ep / 5.f : (mt > 1.2f) ? ep / 10.f : ep / 20.f) |
|||
: ((mt > 6.f) ? ep * 2.f : (mt > 3.f) ? ep : (mt > 1.2f) ? ep / 2.f : ep / 5.f); |
|||
if (inc == 0) |
|||
inc = 1; |
|||
if (o_delta && o_from) |
|||
{ |
|||
(*o_from) = std::floor(uMin / inc) * inc * _divisor; |
|||
(*o_delta) = (std::ceil(uMax / inc) - std::floor(uMin / inc)) * inc * _divisor; |
|||
} |
|||
else if (o_from) |
|||
{ |
|||
(*o_from) = std::ceil(uMin / inc) * inc * _divisor; |
|||
} |
|||
return inc * _divisor; |
|||
} |
|||
|
|||
struct GraphParametersForceMinor { GraphParametersForceMinor() {} }; |
|||
static const GraphParametersForceMinor ForceMinor; |
|||
|
|||
template <class T> |
|||
struct GraphParameters |
|||
{ |
|||
inline GraphParameters(std::pair<T, T> _range, unsigned _divisions) |
|||
{ |
|||
incr = graphParameters(_range.first, _range.second, _divisions, &from, &delta, false); |
|||
to = from + delta; |
|||
} |
|||
|
|||
inline GraphParameters(std::pair<T, T> _range, unsigned _divisions, GraphParametersForceMinor) |
|||
{ |
|||
incr = graphParameters(_range.first, _range.second, _divisions, &from, &delta, true); |
|||
to = from + delta; |
|||
} |
|||
|
|||
inline GraphParameters(std::pair<T, T> _range, unsigned _divisions, T _divisor) |
|||
{ |
|||
major = graphParameters(_range.first, _range.second, _divisions, &from, &delta, false, _divisor); |
|||
incr = graphParameters(_range.first, _range.second, _divisions, &from, &delta, true, _divisor); |
|||
to = from + delta; |
|||
} |
|||
|
|||
template <class S, class Enable = void> |
|||
struct MajorDeterminor { static bool go(S _s, S _j) { S ip; S fp = std::modf(_s / _j + S(0.5), &ip); return fabs(fabs(fp) - 0.5) < 0.05; } }; |
|||
template <class S> |
|||
struct MajorDeterminor<S, typename std::enable_if<std::is_integral<S>::value>::type> { static S go(S _s, S _j) { return _s % _j == 0; } }; |
|||
|
|||
bool isMajor(T _t) const { return MajorDeterminor<T>::go(_t, major); } |
|||
|
|||
T from; |
|||
T delta; |
|||
T major; |
|||
T to; |
|||
T incr; |
|||
}; |
|||
|
|||
} |
@ -0,0 +1,195 @@ |
|||
/* BEGIN COPYRIGHT
|
|||
* |
|||
* This file is part of Noted. |
|||
* |
|||
* Copyright ©2011, 2012, Lancaster Logic Response Limited. |
|||
* |
|||
* Noted 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 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* Noted 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 Noted. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
#include <QtGui/QPainter> |
|||
|
|||
#include "GraphParameters.h" |
|||
#include "Grapher.h" |
|||
|
|||
using namespace std; |
|||
using namespace lb; |
|||
|
|||
void Grapher::init(QPainter* _p, std::pair<float, float> _xRange, std::pair<float, float> _yRange, std::function<std::string(float)> _xLabel, std::function<std::string(float)> _yLabel, std::function<std::string(float, float)> _pLabel, int _leftGutter, int _bottomGutter) |
|||
{ |
|||
fontPixelSize = QFontInfo(QFont("Ubuntu", 10)).pixelSize(); |
|||
|
|||
if (_leftGutter) |
|||
_leftGutter = max<int>(_leftGutter, fontPixelSize * 2); |
|||
if (_bottomGutter) |
|||
_bottomGutter = max<int>(_bottomGutter, fontPixelSize * 1.25); |
|||
|
|||
QRect a(_leftGutter, 0, _p->viewport().width() - _leftGutter, _p->viewport().height() - _bottomGutter); |
|||
init(_p, _xRange, _yRange, _xLabel, _yLabel, _pLabel, a); |
|||
} |
|||
|
|||
bool Grapher::drawAxes(bool _x, bool _y) const |
|||
{ |
|||
int w = active.width(); |
|||
int h = active.height(); |
|||
int l = active.left(); |
|||
int r = active.right(); |
|||
int t = active.top(); |
|||
int b = active.bottom(); |
|||
|
|||
p->setFont(QFont("Ubuntu", 10)); |
|||
p->fillRect(p->viewport(), qRgb(255, 255, 255)); |
|||
|
|||
static const int c_markLength = 2; |
|||
static const int c_markSpacing = 2; |
|||
static const int c_xSpacing = fontPixelSize * 3; |
|||
static const int c_ySpacing = fontPixelSize * 1.25; |
|||
|
|||
if (w < c_xSpacing || h < c_ySpacing || !p->viewport().contains(active)) |
|||
return false; |
|||
|
|||
if (_y) |
|||
{ |
|||
GraphParameters<float> yParams(yRange, h / c_ySpacing, 1.f); |
|||
float dy = fabs(yRange.second - yRange.first); |
|||
if (dy > .001) |
|||
for (float f = yParams.from; f < yParams.to; f += yParams.incr) |
|||
{ |
|||
int y = b - h * (f - yParams.from) / dy; |
|||
if (yParams.isMajor(f)) |
|||
{ |
|||
p->setPen(QColor(208, 208, 208)); |
|||
p->drawLine(l - c_markLength, y, r, y); |
|||
if (l > p->viewport().left()) |
|||
{ |
|||
p->setPen(QColor(144, 144, 144)); |
|||
p->drawText(QRect(0, y - c_ySpacing / 2, l - c_markLength - c_markSpacing, c_ySpacing), Qt::AlignRight|Qt::AlignVCenter, QString::fromStdString(yLabel(round(f * 100000) / 100000))); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
p->setPen(QColor(236, 236, 236)); |
|||
p->drawLine(l, y, r, y); |
|||
} |
|||
} |
|||
p->setPen(QColor(192,192,192)); |
|||
p->drawLine(l - c_markSpacing, b, r, b); |
|||
} |
|||
|
|||
if (_x) |
|||
{ |
|||
GraphParameters<float> xParams(xRange, w / c_xSpacing, 1.f); |
|||
float dx = fabs(xRange.second - xRange.first); |
|||
for (float f = xParams.from; f < xParams.to; f += xParams.incr) |
|||
{ |
|||
int x = l + w * (f - xParams.from) / dx; |
|||
if (xParams.isMajor(f)) |
|||
{ |
|||
p->setPen(QColor(208, 208, 208)); |
|||
p->drawLine(x, t, x, b + c_markLength); |
|||
if (b < p->viewport().bottom()) |
|||
{ |
|||
p->setPen(QColor(144, 144, 144)); |
|||
p->drawText(QRect(x - c_xSpacing / 2, b + c_markLength + c_markSpacing, c_xSpacing, p->viewport().height() - (b + c_markLength + c_markSpacing)), Qt::AlignHCenter|Qt::AlignTop, QString::fromStdString(xLabel(f))); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
p->setPen(QColor(236, 236, 236)); |
|||
p->drawLine(x, t, x, b); |
|||
} |
|||
} |
|||
} |
|||
|
|||
p->setClipRect(active); |
|||
return true; |
|||
} |
|||
|
|||
void Grapher::drawLineGraph(vector<float> const& _data, QColor _color, QBrush const& _fillToZero, float _width) const |
|||
{ |
|||
int s = _data.size(); |
|||
QPoint l; |
|||
for (int i = 0; i < s; ++i) |
|||
{ |
|||
int zy = yP(0.f); |
|||
QPoint h(xTP(i), yTP(_data[i])); |
|||
if (i) |
|||
{ |
|||
if (_fillToZero != Qt::NoBrush) |
|||
{ |
|||
p->setPen(Qt::NoPen); |
|||
p->setBrush(_fillToZero); |
|||
p->drawPolygon(QPolygon(QVector<QPoint>() << QPoint(h.x(), zy) << h << l << QPoint(l.x(), zy))); |
|||
} |
|||
p->setPen(QPen(_color, _width)); |
|||
p->drawLine(QLine(l, h)); |
|||
} |
|||
l = h; |
|||
} |
|||
} |
|||
|
|||
void Grapher::ruleY(float _x, QColor _color, float _width) const |
|||
{ |
|||
p->setPen(QPen(_color, _width)); |
|||
p->drawLine(xTP(_x), active.top(), xTP(_x), active.bottom()); |
|||
} |
|||
|
|||
void Grapher::drawLineGraph(std::function<float(float)> const& _f, QColor _color, QBrush const& _fillToZero, float _width) const |
|||
{ |
|||
QPoint l; |
|||
for (int x = active.left(); x < active.right(); x += 2) |
|||
{ |
|||
int zy = yP(0.f); |
|||
QPoint h(x, yTP(_f(xRU(x)))); |
|||
if (x != active.left()) |
|||
{ |
|||
if (_fillToZero != Qt::NoBrush) |
|||
{ |
|||
p->setPen(Qt::NoPen); |
|||
p->setBrush(_fillToZero); |
|||
p->drawPolygon(QPolygon(QVector<QPoint>() << QPoint(h.x(), zy) << h << l << QPoint(l.x(), zy))); |
|||
} |
|||
p->setPen(QPen(_color, _width)); |
|||
p->drawLine(QLine(l, h)); |
|||
} |
|||
l = h; |
|||
} |
|||
} |
|||
|
|||
void Grapher::labelYOrderedPoints(map<float, float> const& _data, int _maxCount, float _minFactor) const |
|||
{ |
|||
int ly = active.top() + 6; |
|||
int pc = 0; |
|||
if (_data.empty()) |
|||
return; |
|||
float smallestAllowed = prev(_data.end())->first * _minFactor; |
|||
for (auto peaki = _data.rbegin(); peaki != _data.rend(); ++peaki) |
|||
if ((peaki->first > smallestAllowed || _minFactor == 0) && pc < _maxCount) |
|||
{ |
|||
auto peak = *peaki; |
|||
int x = xTP(peak.second); |
|||
int y = yTP(peak.first); |
|||
p->setPen(QColor::fromHsvF(float(pc) / _maxCount, 1.f, 0.5f, 0.5f)); |
|||
p->drawEllipse(QPoint(x, y), 4, 4); |
|||
p->drawLine(x, y - 4, x, ly + 6); |
|||
QString f = QString::fromStdString(pLabel(xT(peak.second), yT(peak.first))); |
|||
int fw = p->fontMetrics().width(f); |
|||
p->drawLine(x + 16 + fw + 2, ly + 6, x, ly + 6); |
|||
p->setPen(QColor::fromHsvF(0, 0.f, .35f)); |
|||
p->fillRect(QRect(x+12, ly-6, fw + 8, 12), QBrush(QColor(255, 255, 255, 160))); |
|||
p->drawText(QRect(x+16, ly-6, 160, 12), Qt::AlignVCenter, f); |
|||
ly += 14; |
|||
++pc; |
|||
} |
|||
} |
@ -0,0 +1,116 @@ |
|||
/* BEGIN COPYRIGHT
|
|||
* |
|||
* This file is part of Noted. |
|||
* |
|||
* Copyright ©2011, 2012, Lancaster Logic Response Limited. |
|||
* |
|||
* Noted 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 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* Noted 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 Noted. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <map> |
|||
#include <vector> |
|||
#include <string> |
|||
#include <utility> |
|||
#include <functional> |
|||
|
|||
#include <QtGui/QBrush> |
|||
#include <QtCore/QRect> |
|||
|
|||
class QPainter; |
|||
|
|||
namespace lb |
|||
{ |
|||
|
|||
class Grapher |
|||
{ |
|||
public: |
|||
Grapher(): p(0) {} |
|||
void init(QPainter* _p, std::pair<float, float> _xRange, std::pair<float, float> _yRange, std::function<std::string(float _f)> _xLabel, std::function<std::string(float _f)> _yLabel, std::function<std::string(float, float)> _pLabel, int _leftGutter = 30, int _bottomGutter = 16); |
|||
void init(QPainter* _p, std::pair<float, float> _xRange, std::pair<float, float> _yRange, std::function<std::string(float _f)> _xLabel, std::function<std::string(float _f)> _yLabel, std::function<std::string(float, float)> _pLabel, QRect _active) |
|||
{ |
|||
p = _p; |
|||
active = _active; |
|||
xRange = _xRange; |
|||
yRange = _yRange; |
|||
dx = xRange.second - xRange.first; |
|||
dy = yRange.second - yRange.first; |
|||
xLabel = _xLabel; |
|||
yLabel = _yLabel; |
|||
pLabel = _pLabel; |
|||
} |
|||
|
|||
void setDataTransform(float _xM, float _xC, float _yM, float _yC) |
|||
{ |
|||
xM = _xM; |
|||
xC = _xC; |
|||
yM = _yM; |
|||
yC = _yC; |
|||
} |
|||
void setDataTransform(float _xM, float _xC) |
|||
{ |
|||
xM = _xM; |
|||
xC = _xC; |
|||
yM = 1.f; |
|||
yC = 0.f; |
|||
} |
|||
void resetDataTransform() { xM = yM = 1.f; xC = yC = 0.f; } |
|||
|
|||
bool drawAxes(bool _x = true, bool _y = true) const; |
|||
void drawLineGraph(std::vector<float> const& _data, QColor _color = QColor(128, 128, 128), QBrush const& _fillToZero = Qt::NoBrush, float _width = 0.f) const; |
|||
void drawLineGraph(std::function<float(float)> const& _f, QColor _color = QColor(128, 128, 128), QBrush const& _fillToZero = Qt::NoBrush, float _width = 0.f) const; |
|||
void ruleX(float _y, QColor _color = QColor(128, 128, 128), float _width = 0.f) const; |
|||
void ruleY(float _x, QColor _color = QColor(128, 128, 128), float _width = 0.f) const; |
|||
void labelYOrderedPoints(std::map<float, float> const& _translatedData, int _maxCount = 20, float _minFactor = .01f) const; |
|||
|
|||
protected: |
|||
QPainter* p; |
|||
QRect active; |
|||
std::pair<float, float> xRange; |
|||
std::pair<float, float> yRange; |
|||
|
|||
float xM; |
|||
float xC; |
|||
float yM; |
|||
float yC; |
|||
|
|||
float dx; |
|||
float dy; |
|||
|
|||
std::function<std::string(float _f)> xLabel; |
|||
std::function<std::string(float _f)> yLabel; |
|||
std::function<std::string(float _x, float _y)> pLabel; |
|||
|
|||
float fontPixelSize; |
|||
|
|||
// Translate from raw indexed data into x/y graph units. Only relevant for indexed data.
|
|||
float xT(float _dataIndex) const { return _dataIndex * xM + xC; } |
|||
float yT(float _dataValue) const { return _dataValue * yM + yC; } |
|||
// Translate from x/y graph units to widget pixels.
|
|||
int xP(float _xUnits) const { return active.left() + (_xUnits - xRange.first) / dx * active.width(); } |
|||
int yP(float _yUnits) const { return active.bottom() - (_yUnits - yRange.first) / dy * active.height(); } |
|||
QPoint P(float _x, float _y) const { return QPoint(xP(_x), yP(_y)); } |
|||
// Translate direcly from raw indexed data to widget pixels.
|
|||
int xTP(float _dataIndex) const { return active.left() + (xT(_dataIndex) - xRange.first) / dx * active.width(); } |
|||
int yTP(float _dataValue) const { return active.bottom() - (yT(_dataValue) - yRange.first) / dy * active.height(); } |
|||
// Translate back from pixels into graph units.
|
|||
float xU(int _xPixels) const { return float(_xPixels - active.left()) / active.width() * dx + xRange.first; } |
|||
// Translate back from graph units into raw data index.
|
|||
float xR(float _xUnits) const { return (_xUnits - xC) / xM; } |
|||
// Translate directly from pixels into raw data index. xRU(xTP(X)) == X
|
|||
float xRU(int _xPixels) const { return xR(xU(_xPixels)); } |
|||
}; |
|||
|
|||
} |
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,118 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file MiningView.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "MiningView.h" |
|||
|
|||
#include <QtWidgets> |
|||
#include <QtCore> |
|||
#include <libethereum/Client.h> |
|||
#include "Grapher.h" |
|||
|
|||
using namespace std; |
|||
using namespace lb; |
|||
|
|||
// do *not* use eth since eth::uint conflicts with Qt's global unit definition
|
|||
// using namespace eth;
|
|||
|
|||
// types
|
|||
|
|||
using eth::MineInfo; |
|||
using eth::MineProgress; |
|||
|
|||
// functions
|
|||
using eth::toString; |
|||
using eth::trimFront; |
|||
|
|||
string id(float _y) { return toString(_y); } |
|||
string s(float _x){ return toString(round(_x * 1000) / 1000) + (!_x ? "s" : ""); } |
|||
string sL(float _x, float _y) { return toString(round(_x * 1000)) + "s (" + toString(_y) + ")"; } |
|||
|
|||
MiningView::MiningView(QWidget* _p): QWidget(_p) |
|||
{ |
|||
|
|||
} |
|||
|
|||
void MiningView::appendStats(list<MineInfo> const& _i, MineProgress const& _p) |
|||
{ |
|||
if (_i.empty()) |
|||
return; |
|||
|
|||
unsigned o = m_values.size(); |
|||
for (MineInfo const& i: _i) |
|||
{ |
|||
m_values.push_back(i.best); |
|||
m_lastBest = min(m_lastBest, i.best); |
|||
m_bests.push_back(m_lastBest); |
|||
m_reqs.push_back(i.requirement); |
|||
if (i.completed) |
|||
{ |
|||
m_completes.push_back(o); |
|||
m_resets.push_back(o); |
|||
m_haveReset = false; |
|||
m_lastBest = 1e99; |
|||
} |
|||
++o; |
|||
} |
|||
if (m_haveReset) |
|||
{ |
|||
m_resets.push_back(o - 1); |
|||
m_lastBest = 1e99; |
|||
m_haveReset = false; |
|||
} |
|||
|
|||
o = max<int>(0, (int)m_values.size() - (int)m_duration); |
|||
trimFront(m_values, o); |
|||
trimFront(m_bests, o); |
|||
trimFront(m_reqs, o); |
|||
|
|||
for (auto& i: m_resets) |
|||
i -= o; |
|||
remove_if(m_resets.begin(), m_resets.end(), [](int i){return i < 0;}); |
|||
for (auto& i: m_completes) |
|||
i -= o; |
|||
remove_if(m_completes.begin(), m_completes.end(), [](int i){return i < 0;}); |
|||
|
|||
m_progress = _p; |
|||
update(); |
|||
} |
|||
|
|||
void MiningView::resetStats() |
|||
{ |
|||
m_haveReset = true; |
|||
} |
|||
|
|||
void MiningView::paintEvent(QPaintEvent*) |
|||
{ |
|||
Grapher g; |
|||
QPainter p(this); |
|||
|
|||
g.init(&p, make_pair(0.f, max((float)m_duration * 0.1f, (float)m_values.size() * 0.1f)), make_pair(0.0f, 255.f - ((float)m_progress.requirement - 4.0f)), s, id, sL); |
|||
g.drawAxes(); |
|||
g.setDataTransform(0.1f, 0, -1.0f, 255.f); |
|||
|
|||
g.drawLineGraph(m_values, QColor(192, 192, 192)); |
|||
g.drawLineGraph(m_bests, QColor(128, 128, 128)); |
|||
g.drawLineGraph(m_reqs, QColor(128, 64, 64)); |
|||
for (auto r: m_resets) |
|||
g.ruleY(r - 1, QColor(128, 128, 128)); |
|||
for (auto r: m_completes) |
|||
g.ruleY(r, QColor(192, 64, 64)); |
|||
} |
@ -0,0 +1,56 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file MiningView.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <list> |
|||
#include <QtWidgets/QWidget> |
|||
#include <libethereum/Client.h> |
|||
|
|||
namespace eth |
|||
{ |
|||
struct MineInfo; |
|||
} |
|||
|
|||
class MiningView: public QWidget |
|||
{ |
|||
Q_OBJECT |
|||
|
|||
public: |
|||
MiningView(QWidget* _p = nullptr); |
|||
|
|||
void appendStats(std::list<eth::MineInfo> const& _l, eth::MineProgress const& _p); |
|||
void resetStats(); |
|||
|
|||
protected: |
|||
virtual void paintEvent(QPaintEvent*); |
|||
|
|||
private: |
|||
eth::MineProgress m_progress; |
|||
unsigned m_duration = 300; |
|||
std::vector<float> m_values; |
|||
std::vector<float> m_bests; |
|||
std::vector<float> m_reqs; |
|||
std::vector<int> m_resets; |
|||
std::vector<int> m_completes; |
|||
double m_lastBest = 1e31; |
|||
bool m_haveReset = false; |
|||
}; |
@ -0,0 +1,50 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process.hpp |
|||
* |
|||
* Convenience header that includes all other Boost.Process public header |
|||
* files. It is important to note that those headers that are specific to |
|||
* a given platform are only included if the library is being used in that |
|||
* same platform. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_HPP |
|||
#define BOOST_PROCESS_HPP |
|||
|
|||
#include <boost/process/config.hpp> |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
# include <boost/process/posix_child.hpp> |
|||
# include <boost/process/posix_context.hpp> |
|||
# include <boost/process/posix_operations.hpp> |
|||
# include <boost/process/posix_status.hpp> |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
# include <boost/process/win32_child.hpp> |
|||
# include <boost/process/win32_context.hpp> |
|||
# include <boost/process/win32_operations.hpp> |
|||
#else |
|||
# error "Unsupported platform." |
|||
#endif |
|||
|
|||
#include <boost/process/child.hpp> |
|||
#include <boost/process/context.hpp> |
|||
#include <boost/process/environment.hpp> |
|||
#include <boost/process/operations.hpp> |
|||
#include <boost/process/pistream.hpp> |
|||
#include <boost/process/postream.hpp> |
|||
#include <boost/process/process.hpp> |
|||
#include <boost/process/self.hpp> |
|||
#include <boost/process/status.hpp> |
|||
#include <boost/process/stream_behavior.hpp> |
|||
|
|||
#endif |
@ -0,0 +1,200 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/child.hpp |
|||
* |
|||
* Includes the declaration of the child class. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_CHILD_HPP |
|||
#define BOOST_PROCESS_CHILD_HPP |
|||
|
|||
#include <boost/process/config.hpp> |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
# include <sys/types.h> |
|||
# include <sys/wait.h> |
|||
# include <cerrno> |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
# include <windows.h> |
|||
#else |
|||
# error "Unsupported platform." |
|||
#endif |
|||
|
|||
#include <boost/process/process.hpp> |
|||
#include <boost/process/pistream.hpp> |
|||
#include <boost/process/postream.hpp> |
|||
#include <boost/process/status.hpp> |
|||
#include <boost/process/detail/file_handle.hpp> |
|||
#include <boost/system/system_error.hpp> |
|||
#include <boost/throw_exception.hpp> |
|||
#include <boost/shared_ptr.hpp> |
|||
#include <boost/assert.hpp> |
|||
#include <vector> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Generic implementation of the Child concept. |
|||
* |
|||
* The child class implements the Child concept in an operating system |
|||
* agnostic way. |
|||
*/ |
|||
class child : public process |
|||
{ |
|||
public: |
|||
/**
|
|||
* Gets a reference to the child's standard input stream. |
|||
* |
|||
* Returns a reference to a postream object that represents the |
|||
* standard input communication channel with the child process. |
|||
*/ |
|||
postream &get_stdin() const |
|||
{ |
|||
BOOST_ASSERT(stdin_); |
|||
|
|||
return *stdin_; |
|||
} |
|||
|
|||
/**
|
|||
* Gets a reference to the child's standard output stream. |
|||
* |
|||
* Returns a reference to a pistream object that represents the |
|||
* standard output communication channel with the child process. |
|||
*/ |
|||
pistream &get_stdout() const |
|||
{ |
|||
BOOST_ASSERT(stdout_); |
|||
|
|||
return *stdout_; |
|||
} |
|||
|
|||
/**
|
|||
* Gets a reference to the child's standard error stream. |
|||
* |
|||
* Returns a reference to a pistream object that represents the |
|||
* standard error communication channel with the child process. |
|||
*/ |
|||
pistream &get_stderr() const |
|||
{ |
|||
BOOST_ASSERT(stderr_); |
|||
|
|||
return *stderr_; |
|||
} |
|||
|
|||
/**
|
|||
* Blocks and waits for the child process to terminate. |
|||
* |
|||
* Returns a status object that represents the child process' |
|||
* finalization condition. The child process object ceases to be |
|||
* valid after this call. |
|||
* |
|||
* \remark Blocking remarks: This call blocks if the child |
|||
* process has not finalized execution and waits until |
|||
* it terminates. |
|||
*/ |
|||
status wait() |
|||
{ |
|||
#if defined(BOOST_POSIX_API) |
|||
int s; |
|||
if (::waitpid(get_id(), &s, 0) == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::child::wait: waitpid(2) failed")); |
|||
return status(s); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
::WaitForSingleObject(process_handle_.get(), INFINITE); |
|||
DWORD code; |
|||
if (!::GetExitCodeProcess(process_handle_.get(), &code)) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::child::wait: GetExitCodeProcess failed")); |
|||
return status(code); |
|||
#endif |
|||
} |
|||
|
|||
/**
|
|||
* Creates a new child object that represents the just spawned child |
|||
* process \a id. |
|||
* |
|||
* The \a fhstdin, \a fhstdout and \a fhstderr file handles represent |
|||
* the parent's handles used to communicate with the corresponding |
|||
* data streams. They needn't be valid but their availability must |
|||
* match the redirections configured by the launcher that spawned this |
|||
* process. |
|||
* |
|||
* The \a fhprocess handle represents a handle to the child process. |
|||
* It is only used on Windows as the implementation of wait() needs a |
|||
* process handle. |
|||
*/ |
|||
child(id_type id, detail::file_handle fhstdin, detail::file_handle fhstdout, detail::file_handle fhstderr, detail::file_handle fhprocess = detail::file_handle()) |
|||
: process(id) |
|||
#if defined(BOOST_WINDOWS_API) |
|||
, process_handle_(fhprocess.release(), ::CloseHandle) |
|||
#endif |
|||
{ |
|||
if (fhstdin.valid()) |
|||
stdin_.reset(new postream(fhstdin)); |
|||
if (fhstdout.valid()) |
|||
stdout_.reset(new pistream(fhstdout)); |
|||
if (fhstderr.valid()) |
|||
stderr_.reset(new pistream(fhstderr)); |
|||
} |
|||
|
|||
private: |
|||
/**
|
|||
* The standard input stream attached to the child process. |
|||
* |
|||
* This postream object holds the communication channel with the |
|||
* child's process standard input. It is stored in a pointer because |
|||
* this field is only valid when the user requested to redirect this |
|||
* data stream. |
|||
*/ |
|||
boost::shared_ptr<postream> stdin_; |
|||
|
|||
/**
|
|||
* The standard output stream attached to the child process. |
|||
* |
|||
* This postream object holds the communication channel with the |
|||
* child's process standard output. It is stored in a pointer because |
|||
* this field is only valid when the user requested to redirect this |
|||
* data stream. |
|||
*/ |
|||
boost::shared_ptr<pistream> stdout_; |
|||
|
|||
/**
|
|||
* The standard error stream attached to the child process. |
|||
* |
|||
* This postream object holds the communication channel with the |
|||
* child's process standard error. It is stored in a pointer because |
|||
* this field is only valid when the user requested to redirect this |
|||
* data stream. |
|||
*/ |
|||
boost::shared_ptr<pistream> stderr_; |
|||
|
|||
#if defined(BOOST_WINDOWS_API) |
|||
/**
|
|||
* Process handle owned by RAII object. |
|||
*/ |
|||
boost::shared_ptr<void> process_handle_; |
|||
#endif |
|||
}; |
|||
|
|||
/**
|
|||
* Collection of child objects. |
|||
* |
|||
* This convenience type represents a collection of child objects backed |
|||
* by a vector. |
|||
*/ |
|||
typedef std::vector<child> children; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,41 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/config.hpp |
|||
* |
|||
* Defines macros that are used by the library's code to determine the |
|||
* operating system it is running under and the features it supports. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_CONFIG_HPP |
|||
#define BOOST_PROCESS_CONFIG_HPP |
|||
|
|||
#include <boost/config.hpp> |
|||
#include <boost/system/config.hpp> |
|||
|
|||
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) |
|||
# if !defined(BOOST_PROCESS_POSIX_PATH_MAX) |
|||
/**
|
|||
* The macro BOOST_PROCESS_POSIX_PATH_MAX is set to a positive integer |
|||
* value which specifies the system's maximal supported path length. |
|||
* By default it is set to 259. You should set the macro to PATH_MAX |
|||
* which should be defined in limits.h provided by your operating system |
|||
* if you experience problems when instantiating a context. The |
|||
* constructor of basic_work_directory_context tries to find out |
|||
* dynamically the maximal supported path length but uses |
|||
* BOOST_PROCESS_POSIX_PATH_MAX if it fails. |
|||
*/ |
|||
# define BOOST_PROCESS_POSIX_PATH_MAX 259 |
|||
# endif |
|||
#endif |
|||
|
|||
#endif |
@ -0,0 +1,209 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/context.hpp |
|||
* |
|||
* Includes the declaration of the context class and several accessory |
|||
* base classes. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_CONTEXT_HPP |
|||
#define BOOST_PROCESS_CONTEXT_HPP |
|||
|
|||
#include <boost/process/config.hpp> |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
# include <boost/scoped_array.hpp> |
|||
# include <cerrno> |
|||
# include <unistd.h> |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
# include <windows.h> |
|||
#else |
|||
# error "Unsupported platform." |
|||
#endif |
|||
|
|||
#include <boost/process/environment.hpp> |
|||
#include <boost/process/stream_behavior.hpp> |
|||
#include <boost/system/system_error.hpp> |
|||
#include <boost/throw_exception.hpp> |
|||
#include <boost/assert.hpp> |
|||
#include <string> |
|||
#include <vector> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Base context class that defines the child's work directory. |
|||
* |
|||
* Base context class that defines the necessary fields to configure a |
|||
* child's work directory. This class is useless on its own because no |
|||
* function in the library will accept it as a valid Context |
|||
* implementation. |
|||
*/ |
|||
template <class Path> |
|||
class basic_work_directory_context |
|||
{ |
|||
public: |
|||
/**
|
|||
* Constructs a new work directory context. |
|||
* |
|||
* Constructs a new work directory context making the work directory |
|||
* described by the new object point to the caller's current working |
|||
* directory. |
|||
*/ |
|||
basic_work_directory_context() |
|||
{ |
|||
#if defined(BOOST_POSIX_API) |
|||
errno = 0; |
|||
long size = ::pathconf(".", _PC_PATH_MAX); |
|||
if (size == -1 && errno) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: pathconf(2) failed")); |
|||
else if (size == -1) |
|||
size = BOOST_PROCESS_POSIX_PATH_MAX; |
|||
boost::scoped_array<char> cwd(new char[size]); |
|||
if (!::getcwd(cwd.get(), size)) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: getcwd(2) failed")); |
|||
work_directory = cwd.get(); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
char cwd[MAX_PATH]; |
|||
if (!::GetCurrentDirectoryA(sizeof(cwd), cwd)) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::basic_work_directory_context::basic_work_directory_context: GetCurrentDirectory failed")); |
|||
work_directory = cwd; |
|||
#endif |
|||
BOOST_ASSERT(!work_directory.empty()); |
|||
} |
|||
|
|||
/**
|
|||
* The process' initial work directory. |
|||
* |
|||
* The work directory is the directory in which the process starts |
|||
* execution. |
|||
*/ |
|||
Path work_directory; |
|||
}; |
|||
|
|||
/**
|
|||
* Base context class that defines the child's environment. |
|||
* |
|||
* Base context class that defines the necessary fields to configure a |
|||
* child's environment variables. This class is useless on its own |
|||
* because no function in the library will accept it as a valid Context |
|||
* implementation. |
|||
*/ |
|||
class environment_context |
|||
{ |
|||
public: |
|||
/**
|
|||
* The process' environment. |
|||
* |
|||
* Contains the list of environment variables, alongside with their |
|||
* values, that will be passed to the spawned child process. |
|||
*/ |
|||
boost::process::environment environment; |
|||
}; |
|||
|
|||
/**
|
|||
* Process startup execution context. |
|||
* |
|||
* The context class groups all the parameters needed to configure a |
|||
* process' environment during its creation. |
|||
*/ |
|||
template <class Path> |
|||
class basic_context : public basic_work_directory_context<Path>, public environment_context |
|||
{ |
|||
public: |
|||
/**
|
|||
* Child's stdin behavior. |
|||
*/ |
|||
stream_behavior stdin_behavior; |
|||
|
|||
/**
|
|||
* Child's stdout behavior. |
|||
*/ |
|||
stream_behavior stdout_behavior; |
|||
|
|||
/**
|
|||
* Child's stderr behavior. |
|||
*/ |
|||
stream_behavior stderr_behavior; |
|||
}; |
|||
|
|||
typedef basic_context<std::string> context; |
|||
|
|||
/**
|
|||
* Represents a child process in a pipeline. |
|||
* |
|||
* This convenience class is a triplet that holds all the data required |
|||
* to spawn a new child process in a pipeline. |
|||
*/ |
|||
template <class Executable, class Arguments, class Context> |
|||
class basic_pipeline_entry |
|||
{ |
|||
public: |
|||
/**
|
|||
* The executable to launch. |
|||
*/ |
|||
Executable executable; |
|||
|
|||
/**
|
|||
* The set of arguments to pass to the executable. |
|||
*/ |
|||
Arguments arguments; |
|||
|
|||
/**
|
|||
* The child's execution context. |
|||
*/ |
|||
Context context; |
|||
|
|||
/**
|
|||
* The type of the Executable concept used in this template |
|||
* instantiation. |
|||
*/ |
|||
typedef Executable executable_type; |
|||
|
|||
/**
|
|||
* The type of the Arguments concept used in this template |
|||
* instantiation. |
|||
*/ |
|||
typedef Arguments arguments_type; |
|||
|
|||
/**
|
|||
* The type of the Context concept used in this template |
|||
* instantiation. |
|||
*/ |
|||
typedef Context context_type; |
|||
|
|||
/**
|
|||
* Constructs a new pipeline_entry object. |
|||
* |
|||
* Given the executable, set of arguments and execution triplet, |
|||
* constructs a new pipeline_entry object that holds the three |
|||
* values. |
|||
*/ |
|||
basic_pipeline_entry(const Executable &exe, const Arguments &args, const Context &ctx) |
|||
: executable(exe), |
|||
arguments(args), |
|||
context(ctx) |
|||
{ |
|||
} |
|||
}; |
|||
|
|||
/**
|
|||
* Default instantiation of basic_pipeline_entry. |
|||
*/ |
|||
typedef basic_pipeline_entry<std::string, std::vector<std::string>, context> pipeline_entry; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,406 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/detail/file_handle.hpp |
|||
* |
|||
* Includes the declaration of the file_handle class. This file is for |
|||
* internal usage only and must not be included by the library user. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_DETAIL_FILE_HANDLE_HPP |
|||
#define BOOST_PROCESS_DETAIL_FILE_HANDLE_HPP |
|||
|
|||
#include <boost/process/config.hpp> |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
# include <cerrno> |
|||
# include <unistd.h> |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
# include <windows.h> |
|||
#else |
|||
# error "Unsupported platform." |
|||
#endif |
|||
|
|||
#include <boost/assert.hpp> |
|||
#include <boost/system/system_error.hpp> |
|||
#include <boost/throw_exception.hpp> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
namespace detail { |
|||
|
|||
/**
|
|||
* Simple RAII model for system file handles. |
|||
* |
|||
* The \a file_handle class is a simple RAII model for native system file |
|||
* handles. This class wraps one of such handles grabbing its ownership, |
|||
* and automaticaly closes it upon destruction. It is basically used |
|||
* inside the library to avoid leaking open file handles, shall an |
|||
* unexpected execution trace occur. |
|||
* |
|||
* A \a file_handle object can be copied but doing so invalidates the |
|||
* source object. There can only be a single valid \a file_handle object |
|||
* for a given system file handle. This is similar to std::auto_ptr's |
|||
* semantics. |
|||
* |
|||
* This class also provides some convenience methods to issue special file |
|||
* operations under their respective platforms. |
|||
*/ |
|||
class file_handle |
|||
{ |
|||
public: |
|||
#if defined(BOOST_PROCESS_DOXYGEN) |
|||
/**
|
|||
* Opaque name for the native handle type. |
|||
* |
|||
* Each operating system identifies file handles using a specific type. |
|||
* The \a handle_type type is used to transparently refer to file |
|||
* handles regarless of the operating system in which this class is |
|||
* used. |
|||
* |
|||
* If this class is used on a POSIX system, \a NativeSystemHandle is |
|||
* an integer type while it is a \a HANDLE on a Windows system. |
|||
*/ |
|||
typedef NativeSystemHandle handle_type; |
|||
#elif defined(BOOST_POSIX_API) |
|||
typedef int handle_type; |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
typedef HANDLE handle_type; |
|||
#endif |
|||
|
|||
/**
|
|||
* Constructs an invalid file handle. |
|||
* |
|||
* This constructor creates a new \a file_handle object that represents |
|||
* an invalid file handle. An invalid file handle can be copied but |
|||
* cannot be manipulated in any way (except checking for its validity). |
|||
* |
|||
* \see valid() |
|||
*/ |
|||
file_handle() |
|||
: handle_(invalid_value()) |
|||
{ |
|||
} |
|||
|
|||
/**
|
|||
* Constructs a new file handle from a native file handle. |
|||
* |
|||
* This constructor creates a new \a file_handle object that takes |
|||
* ownership of the given \a h native file handle. The user must not |
|||
* close \a h on his own during the lifetime of the new object. |
|||
* Ownership can be reclaimed using release(). |
|||
* |
|||
* \pre The native file handle must be valid; a close operation must |
|||
* succeed on it. |
|||
* \see release() |
|||
*/ |
|||
file_handle(handle_type h) |
|||
: handle_(h) |
|||
{ |
|||
BOOST_ASSERT(handle_ != invalid_value()); |
|||
} |
|||
|
|||
/**
|
|||
* Copy constructor; invalidates the source handle. |
|||
* |
|||
* This copy constructor creates a new file handle from a given one. |
|||
* Ownership of the native file handle is transferred to the new |
|||
* object, effectively invalidating the source file handle. This |
|||
* avoids having two live \a file_handle objects referring to the |
|||
* same native file handle. The source file handle needs not be |
|||
* valid in the name of simplicity. |
|||
* |
|||
* \post The source file handle is invalid. |
|||
* \post The new file handle owns the source's native file handle. |
|||
*/ |
|||
file_handle(const file_handle &fh) |
|||
: handle_(fh.handle_) |
|||
{ |
|||
fh.handle_ = invalid_value(); |
|||
} |
|||
|
|||
/**
|
|||
* Releases resources if the handle is valid. |
|||
* |
|||
* If the file handle is valid, the destructor closes it. |
|||
* |
|||
* \see valid() |
|||
*/ |
|||
~file_handle() |
|||
{ |
|||
if (valid()) |
|||
close(); |
|||
} |
|||
|
|||
/**
|
|||
* Assignment operator; invalidates the source handle. |
|||
* |
|||
* This assignment operator transfers ownership of the RHS file |
|||
* handle to the LHS one, effectively invalidating the source file |
|||
* handle. This avoids having two live \a file_handle objects |
|||
* referring to the same native file handle. The source file |
|||
* handle needs not be valid in the name of simplicity. |
|||
* |
|||
* \post The RHS file handle is invalid. |
|||
* \post The LHS file handle owns RHS' native file handle. |
|||
* \return A reference to the LHS file handle. |
|||
*/ |
|||
file_handle &operator=(const file_handle &fh) |
|||
{ |
|||
handle_ = fh.handle_; |
|||
fh.handle_ = invalid_value(); |
|||
return *this; |
|||
} |
|||
|
|||
/**
|
|||
* Checks whether the file handle is valid or not. |
|||
* |
|||
* Returns a boolean indicating whether the file handle is valid or |
|||
* not. If the file handle is invalid, no other methods can be |
|||
* executed other than the destructor. |
|||
* |
|||
* \return true if the file handle is valid; false otherwise. |
|||
*/ |
|||
bool valid() const |
|||
{ |
|||
return handle_ != invalid_value(); |
|||
} |
|||
|
|||
/**
|
|||
* Closes the file handle. |
|||
* |
|||
* Explicitly closes the file handle, which must be valid. Upon |
|||
* exit, the handle is not valid any more. |
|||
* |
|||
* \pre The file handle is valid. |
|||
* \post The file handle is invalid. |
|||
* \post The native file handle is closed. |
|||
*/ |
|||
void close() |
|||
{ |
|||
BOOST_ASSERT(valid()); |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
::close(handle_); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
::CloseHandle(handle_); |
|||
#endif |
|||
|
|||
handle_ = invalid_value(); |
|||
} |
|||
|
|||
/**
|
|||
* Reclaims ownership of the native file handle. |
|||
* |
|||
* Explicitly reclaims ownership of the native file handle contained |
|||
* in the \a file_handle object, returning the native file handle. |
|||
* The caller is responsible of closing it later on. |
|||
* |
|||
* \pre The file handle is valid. |
|||
* \post The file handle is invalid. |
|||
* \return The native file handle. |
|||
*/ |
|||
handle_type release() |
|||
{ |
|||
BOOST_ASSERT(valid()); |
|||
|
|||
handle_type h = handle_; |
|||
handle_ = invalid_value(); |
|||
return h; |
|||
} |
|||
|
|||
/**
|
|||
* Gets the native file handle. |
|||
* |
|||
* Returns the native file handle for the \a file_handle object. |
|||
* The caller can issue any operation on it except closing it. |
|||
* If closing is required, release() shall be used. |
|||
* |
|||
* \pre The file handle is valid. |
|||
* \post The file handle is valid. |
|||
* \return The native file handle. |
|||
*/ |
|||
handle_type get() const |
|||
{ |
|||
BOOST_ASSERT(valid()); |
|||
|
|||
return handle_; |
|||
} |
|||
|
|||
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) |
|||
/**
|
|||
* Changes the native file handle to the given one. |
|||
* |
|||
* Given a new native file handle \a h, this operation assigns this |
|||
* handle to the current object, closing its old native file handle. |
|||
* In other words, it first calls dup2() to remap the old handle to |
|||
* the new one and then closes the old handle. |
|||
* |
|||
* If \a h is open, it is automatically closed by dup2(). |
|||
* |
|||
* This operation is only available in POSIX systems. |
|||
* |
|||
* \pre The file handle is valid. |
|||
* \pre The native file handle \a h is valid; i.e., it must be |
|||
* closeable. |
|||
* \post The file handle's native file handle is \a h. |
|||
* \throw boost::system::system_error If the internal remapping |
|||
* operation fails. |
|||
*/ |
|||
void posix_remap(handle_type h) |
|||
{ |
|||
BOOST_ASSERT(valid()); |
|||
|
|||
if (::dup2(handle_, h) == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_remap: dup2(2) failed")); |
|||
|
|||
if (::close(handle_) == -1) |
|||
{ |
|||
::close(h); |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_remap: close(2) failed")); |
|||
} |
|||
|
|||
handle_ = h; |
|||
} |
|||
|
|||
/**
|
|||
* Duplicates an open native file handle. |
|||
* |
|||
* Given a native file handle \a h1, this routine duplicates it so |
|||
* that it ends up being identified by the native file handle \a h2 |
|||
* and returns a new \a file_handle owning \a h2. |
|||
* |
|||
* This operation is only available in POSIX systems. |
|||
* |
|||
* \pre The native file handle \a h1 is open. |
|||
* \pre The native file handle \a h2 is valid (non-negative). |
|||
* \post The native file handle \a h1 is closed. |
|||
* \post The native file handle \a h2 is the same as the old \a h1 |
|||
* from the operating system's point of view. |
|||
* \return A new \a file_handle object that owns \a h2. |
|||
* \throw boost::system::system_error If dup2() fails. |
|||
*/ |
|||
static file_handle posix_dup(int h1, int h2) |
|||
{ |
|||
if (::dup2(h1, h2) == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::file_handle::posix_dup: dup2(2) failed")); |
|||
|
|||
return file_handle(h2); |
|||
} |
|||
#endif |
|||
|
|||
#if defined(BOOST_WINDOWS_API) || defined(BOOST_PROCESS_DOXYGEN) |
|||
/**
|
|||
* Duplicates the \a h native file handle. |
|||
* |
|||
* Given a native file handle \a h, this routine constructs a new |
|||
* \a file_handle object that owns a new duplicate of \a h. The |
|||
* duplicate's inheritable flag is set to the value of \a inheritable. |
|||
* |
|||
* This operation is only available in Windows systems. |
|||
* |
|||
* \pre The native file handle \a h is valid. |
|||
* \return A file handle owning a duplicate of \a h. |
|||
* \throw boost::system::system_error If DuplicateHandle() fails. |
|||
*/ |
|||
static file_handle win32_dup(HANDLE h, bool inheritable) |
|||
{ |
|||
HANDLE h2; |
|||
if (!::DuplicateHandle(::GetCurrentProcess(), h, ::GetCurrentProcess(), &h2, 0, inheritable ? TRUE : FALSE, DUPLICATE_SAME_ACCESS)) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_dup: DuplicateHandle failed")); |
|||
|
|||
return file_handle(h2); |
|||
} |
|||
|
|||
/**
|
|||
* Creates a new duplicate of a standard file handle. |
|||
* |
|||
* Constructs a new \a file_handle object that owns a duplicate of a |
|||
* standard file handle. The \a d parameter specifies which standard |
|||
* file handle to duplicate and can be one of \a STD_INPUT_HANDLE, |
|||
* \a STD_OUTPUT_HANDLE or \a STD_ERROR_HANDLE. The duplicate's |
|||
* inheritable flag is set to the value of \a inheritable. |
|||
* |
|||
* This operation is only available in Windows systems. |
|||
* |
|||
* \pre \a d refers to one of the standard handles as described above. |
|||
* \return A file handle owning a duplicate of the standard handle |
|||
* referred to by \a d. |
|||
* \throw boost::system::system_error If GetStdHandle() or |
|||
* DuplicateHandle() fails. |
|||
*/ |
|||
static file_handle win32_std(DWORD d, bool inheritable) |
|||
{ |
|||
BOOST_ASSERT(d == STD_INPUT_HANDLE || d == STD_OUTPUT_HANDLE || d == STD_ERROR_HANDLE); |
|||
|
|||
HANDLE h = ::GetStdHandle(d); |
|||
if (h == INVALID_HANDLE_VALUE) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_std: GetStdHandle failed")); |
|||
|
|||
return win32_dup(h, inheritable); |
|||
} |
|||
|
|||
/**
|
|||
* Changes the file handle's inheritable flag. |
|||
* |
|||
* Changes the file handle's inheritable flag to \a i. It is not |
|||
* necessary for the file handle's flag to be different than \a i. |
|||
* |
|||
* This operation is only available in Windows systems. |
|||
* |
|||
* \pre The file handle is valid. |
|||
* \post The native file handle's inheritable flag is set to \a i. |
|||
* \throw boost::system::system_error If the property change fails. |
|||
*/ |
|||
void win32_set_inheritable(bool i) |
|||
{ |
|||
BOOST_ASSERT(valid()); |
|||
|
|||
if (!::SetHandleInformation(handle_, HANDLE_FLAG_INHERIT, i ? HANDLE_FLAG_INHERIT : 0)) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::file_handle::win32_set_inheritable: SetHandleInformation failed")); |
|||
} |
|||
#endif |
|||
|
|||
private: |
|||
/**
|
|||
* Internal handle value. |
|||
* |
|||
* This variable holds the native handle value for the file handle |
|||
* hold by this object. It is interesting to note that this needs |
|||
* to be mutable because the copy constructor and the assignment |
|||
* operator invalidate the source object. |
|||
*/ |
|||
mutable handle_type handle_; |
|||
|
|||
/**
|
|||
* Constant function representing an invalid handle value. |
|||
* |
|||
* Returns the platform-specific handle value that represents an |
|||
* invalid handle. This is a constant function rather than a regular |
|||
* constant because, in the latter case, we cannot define it under |
|||
* Windows due to the value being of a complex type. |
|||
*/ |
|||
static handle_type invalid_value() |
|||
{ |
|||
#if defined(BOOST_POSIX_API) |
|||
return -1; |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
return INVALID_HANDLE_VALUE; |
|||
#endif |
|||
} |
|||
}; |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,187 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/detail/pipe.hpp |
|||
* |
|||
* Includes the declaration of the pipe class. This file is for |
|||
* internal usage only and must not be included by the library user. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_DETAIL_PIPE_HPP |
|||
#define BOOST_PROCESS_DETAIL_PIPE_HPP |
|||
|
|||
#include <boost/process/config.hpp> |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
# include <unistd.h> |
|||
# include <cerrno> |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
# if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE) |
|||
# include <boost/lexical_cast.hpp> |
|||
# include <string> |
|||
# endif |
|||
# include <windows.h> |
|||
#else |
|||
# error "Unsupported platform." |
|||
#endif |
|||
|
|||
#include <boost/process/detail/file_handle.hpp> |
|||
#include <boost/system/system_error.hpp> |
|||
#include <boost/throw_exception.hpp> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
namespace detail { |
|||
|
|||
/**
|
|||
* Simple RAII model for anonymous pipes. |
|||
* |
|||
* The pipe class is a simple RAII model for anonymous pipes. It |
|||
* provides a portable constructor that allocates a new %pipe and creates |
|||
* a pipe object that owns the two file handles associated to it: the |
|||
* read end and the write end. |
|||
* |
|||
* These handles can be retrieved for modification according to |
|||
* file_handle semantics. Optionally, their ownership can be transferred |
|||
* to external \a file_handle objects which comes handy when the two |
|||
* ends need to be used in different places (i.e. after a POSIX fork() |
|||
* system call). |
|||
* |
|||
* Pipes can be copied following the same semantics as file handles. |
|||
* In other words, copying a %pipe object invalidates the source one. |
|||
* |
|||
* \see file_handle |
|||
*/ |
|||
class pipe |
|||
{ |
|||
public: |
|||
/**
|
|||
* Creates a new %pipe. |
|||
* |
|||
* The default pipe constructor allocates a new anonymous %pipe |
|||
* and assigns its ownership to the created pipe object. On Windows |
|||
* when the macro BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE is defined |
|||
* a named pipe is created. This is required if asynchronous I/O |
|||
* should be used as asynchronous I/O is only supported by named |
|||
* pipes on Windows. |
|||
* |
|||
* \throw boost::system::system_error If the anonymous %pipe |
|||
* creation fails. |
|||
*/ |
|||
pipe() |
|||
{ |
|||
file_handle::handle_type hs[2]; |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
if (::pipe(hs) == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::pipe::pipe: pipe(2) failed")); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
SECURITY_ATTRIBUTES sa; |
|||
ZeroMemory(&sa, sizeof(sa)); |
|||
sa.nLength = sizeof(sa); |
|||
sa.lpSecurityDescriptor = NULL; |
|||
sa.bInheritHandle = FALSE; |
|||
|
|||
# if defined(BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE) |
|||
static unsigned int nextid = 0; |
|||
std::string pipe = "\\\\.\\pipe\\boost_process_" + boost::lexical_cast<std::string>(::GetCurrentProcessId()) + "_" + boost::lexical_cast<std::string>(nextid++); |
|||
hs[0] = ::CreateNamedPipeA(pipe.c_str(), PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, &sa); |
|||
if (hs[0] == INVALID_HANDLE_VALUE) |
|||
boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateNamedPipe failed")); |
|||
hs[1] = ::CreateFileA(pipe.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); |
|||
if (hs[1] == INVALID_HANDLE_VALUE) |
|||
boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateFile failed")); |
|||
|
|||
OVERLAPPED overlapped; |
|||
ZeroMemory(&overlapped, sizeof(overlapped)); |
|||
overlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL); |
|||
if (!overlapped.hEvent) |
|||
boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreateEvent failed")); |
|||
BOOL b = ::ConnectNamedPipe(hs[0], &overlapped); |
|||
if (!b) |
|||
{ |
|||
if (::GetLastError() == ERROR_IO_PENDING) |
|||
{ |
|||
if (::WaitForSingleObject(overlapped.hEvent, INFINITE) == WAIT_FAILED) |
|||
{ |
|||
::CloseHandle(overlapped.hEvent); |
|||
boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: WaitForSingleObject failed")); |
|||
} |
|||
} |
|||
else if (::GetLastError() != ERROR_PIPE_CONNECTED) |
|||
{ |
|||
::CloseHandle(overlapped.hEvent); |
|||
boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: ConnectNamedPipe failed")); |
|||
} |
|||
} |
|||
::CloseHandle(overlapped.hEvent); |
|||
# else |
|||
if (!::CreatePipe(&hs[0], &hs[1], &sa, 0)) |
|||
boost::throw_exception(boost::system::system_error(::GetLastError(), boost::system::system_category(), "boost::process::detail::pipe::pipe: CreatePipe failed")); |
|||
# endif |
|||
#endif |
|||
|
|||
read_end_ = file_handle(hs[0]); |
|||
write_end_ = file_handle(hs[1]); |
|||
} |
|||
|
|||
/**
|
|||
* Returns the %pipe's read end file handle. |
|||
* |
|||
* Obtains a reference to the %pipe's read end file handle. Care |
|||
* should be taken to not duplicate the returned object if ownership |
|||
* shall remain to the %pipe. |
|||
* |
|||
* Duplicating the returned object invalidates its corresponding file |
|||
* handle in the %pipe. |
|||
* |
|||
* \return A reference to the %pipe's read end file handle. |
|||
*/ |
|||
file_handle &rend() |
|||
{ |
|||
return read_end_; |
|||
} |
|||
|
|||
/**
|
|||
* Returns the %pipe's write end file handle. |
|||
* |
|||
* Obtains a reference to the %pipe's write end file handle. Care |
|||
* should be taken to not duplicate the returned object if ownership |
|||
* shall remain to the %pipe. |
|||
* |
|||
* Duplicating the returned object invalidates its corresponding file |
|||
* handle in the %pipe. |
|||
* |
|||
* \return A reference to the %pipe's write end file handle. |
|||
*/ |
|||
file_handle &wend() |
|||
{ |
|||
return write_end_; |
|||
} |
|||
|
|||
private: |
|||
/**
|
|||
* The %pipe's read end file handle. |
|||
*/ |
|||
file_handle read_end_; |
|||
|
|||
/**
|
|||
* The %pipe's write end file handle. |
|||
*/ |
|||
file_handle write_end_; |
|||
}; |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,495 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/detail/posix_ops.hpp |
|||
* |
|||
* Provides some convenience functions to start processes under POSIX |
|||
* operating systems. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_DETAIL_POSIX_OPS_HPP |
|||
#define BOOST_PROCESS_DETAIL_POSIX_OPS_HPP |
|||
|
|||
#include <boost/process/environment.hpp> |
|||
#include <boost/process/detail/file_handle.hpp> |
|||
#include <boost/process/detail/pipe.hpp> |
|||
#include <boost/process/detail/stream_info.hpp> |
|||
#include <boost/scoped_array.hpp> |
|||
#include <boost/assert.hpp> |
|||
#include <boost/system/system_error.hpp> |
|||
#include <boost/throw_exception.hpp> |
|||
#include <map> |
|||
#include <utility> |
|||
#include <string> |
|||
#include <cerrno> |
|||
#include <cstdlib> |
|||
#include <cstring> |
|||
#include <fcntl.h> |
|||
#include <unistd.h> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
namespace detail { |
|||
|
|||
/**
|
|||
* Converts the command line to an array of C strings. |
|||
* |
|||
* Converts the command line's list of arguments to the format expected |
|||
* by the \a argv parameter in the POSIX execve() system call. |
|||
* |
|||
* This operation is only available on POSIX systems. |
|||
* |
|||
* \return The first argument of the pair is an integer that indicates |
|||
* how many strings are stored in the second argument. The |
|||
* second argument is a NULL-terminated, dynamically allocated |
|||
* array of dynamically allocated strings holding the arguments |
|||
* to the executable. The caller is responsible of freeing them. |
|||
*/ |
|||
template <class Arguments> |
|||
inline std::pair<std::size_t, char**> collection_to_posix_argv(const Arguments &args) |
|||
{ |
|||
std::size_t nargs = args.size(); |
|||
BOOST_ASSERT(nargs > 0); |
|||
|
|||
char **argv = new char*[nargs + 1]; |
|||
typename Arguments::size_type i = 0; |
|||
for (typename Arguments::const_iterator it = args.begin(); it != args.end(); ++it) |
|||
{ |
|||
argv[i] = new char[it->size() + 1]; |
|||
std::strncpy(argv[i], it->c_str(), it->size() + 1); |
|||
++i; |
|||
} |
|||
argv[nargs] = 0; |
|||
|
|||
return std::pair<std::size_t, char**>(nargs, argv); |
|||
} |
|||
|
|||
/**
|
|||
* Converts an environment to a char** table as used by execve(). |
|||
* |
|||
* Converts the environment's contents to the format used by the |
|||
* execve() system call. The returned char** array is allocated |
|||
* in dynamic memory; the caller must free it when not used any |
|||
* more. Each entry is also allocated in dynamic memory and is a |
|||
* NULL-terminated string of the form var=value; these must also be |
|||
* released by the caller. |
|||
* |
|||
* \return A dynamically allocated char** array that represents |
|||
* the environment's content. Each array entry is a |
|||
* NULL-terminated string of the form var=value. |
|||
*/ |
|||
inline char **environment_to_envp(const environment &env) |
|||
{ |
|||
char **envp = new char*[env.size() + 1]; |
|||
|
|||
environment::size_type i = 0; |
|||
for (environment::const_iterator it = env.begin(); it != env.end(); ++it) |
|||
{ |
|||
std::string s = it->first + "=" + it->second; |
|||
envp[i] = new char[s.size() + 1]; |
|||
std::strncpy(envp[i], s.c_str(), s.size() + 1); |
|||
++i; |
|||
} |
|||
envp[i] = 0; |
|||
|
|||
return envp; |
|||
} |
|||
|
|||
/**
|
|||
* Holds a mapping between native file descriptors and their corresponding |
|||
* pipes to set up communication between the parent and the %child process. |
|||
*/ |
|||
typedef std::map<int, stream_info> info_map; |
|||
|
|||
/**
|
|||
* Helper class to configure a POSIX %child. |
|||
* |
|||
* This helper class is used to hold all the attributes that configure a |
|||
* new POSIX %child process and to centralize all the actions needed to |
|||
* make them effective. |
|||
* |
|||
* All its fields are public for simplicity. It is only intended for |
|||
* internal use and it is heavily coupled with the Context |
|||
* implementations. |
|||
*/ |
|||
struct posix_setup |
|||
{ |
|||
/**
|
|||
* The work directory. |
|||
* |
|||
* This string specifies the directory in which the %child process |
|||
* starts execution. It cannot be empty. |
|||
*/ |
|||
std::string work_directory; |
|||
|
|||
/**
|
|||
* The chroot directory, if any. |
|||
* |
|||
* Specifies the directory in which the %child process is chrooted |
|||
* before execution. Empty if this feature is not desired. |
|||
*/ |
|||
std::string chroot; |
|||
|
|||
/**
|
|||
* The user credentials. |
|||
* |
|||
* UID that specifies the user credentials to use to run the %child |
|||
* process. Defaults to the current UID. |
|||
*/ |
|||
uid_t uid; |
|||
|
|||
/**
|
|||
* The effective user credentials. |
|||
* |
|||
* EUID that specifies the effective user credentials to use to run |
|||
* the %child process. Defaults to the current EUID. |
|||
*/ |
|||
uid_t euid; |
|||
|
|||
/**
|
|||
* The group credentials. |
|||
* |
|||
* GID that specifies the group credentials to use to run the %child |
|||
* process. Defaults to the current GID. |
|||
*/ |
|||
gid_t gid; |
|||
|
|||
/**
|
|||
* The effective group credentials. |
|||
* |
|||
* EGID that specifies the effective group credentials to use to run |
|||
* the %child process. Defaults to the current EGID. |
|||
*/ |
|||
gid_t egid; |
|||
|
|||
/**
|
|||
* Creates a new properties set. |
|||
* |
|||
* Creates a new object that has sensible default values for all the |
|||
* properties. |
|||
*/ |
|||
posix_setup() |
|||
: uid(::getuid()), |
|||
euid(::geteuid()), |
|||
gid(::getgid()), |
|||
egid(::getegid()) |
|||
{ |
|||
} |
|||
|
|||
/**
|
|||
* Sets up the execution environment. |
|||
* |
|||
* Modifies the current execution environment (that of the %child) so |
|||
* that the properties become effective. |
|||
* |
|||
* \throw boost::system::system_error If any error ocurred during |
|||
* environment configuration. The child process should abort |
|||
* execution if this happens because its start conditions |
|||
* cannot be met. |
|||
*/ |
|||
void operator()() const |
|||
{ |
|||
if (!chroot.empty() && ::chroot(chroot.c_str()) == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: chroot(2) failed")); |
|||
|
|||
if (gid != ::getgid() && ::setgid(gid) == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setgid(2) failed")); |
|||
|
|||
if (egid != ::getegid() && ::setegid(egid) == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setegid(2) failed")); |
|||
|
|||
if (uid != ::getuid() && ::setuid(uid) == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: setuid(2) failed")); |
|||
|
|||
if (euid != ::geteuid() && ::seteuid(euid) == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: seteuid(2) failed")); |
|||
|
|||
BOOST_ASSERT(!work_directory.empty()); |
|||
if (::chdir(work_directory.c_str()) == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_setup: chdir(2) failed")); |
|||
} |
|||
}; |
|||
|
|||
/**
|
|||
* Configures child process' input streams. |
|||
* |
|||
* Sets up the current process' input streams to behave according to the |
|||
* information in the \a info map. \a closeflags is modified to reflect |
|||
* those descriptors that should not be closed because they where modified |
|||
* by the function. |
|||
* |
|||
* Modifies the current execution environment, so this should only be run |
|||
* on the child process after the fork(2) has happened. |
|||
* |
|||
* \throw boost::system::system_error If any error occurs during the |
|||
* configuration. |
|||
*/ |
|||
inline void setup_input(info_map &info, bool *closeflags, int maxdescs) |
|||
{ |
|||
for (info_map::iterator it = info.begin(); it != info.end(); ++it) |
|||
{ |
|||
int d = it->first; |
|||
stream_info &si = it->second; |
|||
|
|||
BOOST_ASSERT(d < maxdescs); |
|||
closeflags[d] = false; |
|||
|
|||
switch (si.type_) |
|||
{ |
|||
case stream_info::use_file: |
|||
{ |
|||
int fd = ::open(si.file_.c_str(), O_RDONLY); |
|||
if (fd == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::setup_input: open(2) of " + si.file_ + " failed")); |
|||
if (fd != d) |
|||
{ |
|||
file_handle h(fd); |
|||
h.posix_remap(d); |
|||
h.release(); |
|||
} |
|||
break; |
|||
} |
|||
case stream_info::use_handle: |
|||
{ |
|||
if (si.handle_.get() != d) |
|||
si.handle_.posix_remap(d); |
|||
break; |
|||
} |
|||
case stream_info::use_pipe: |
|||
{ |
|||
si.pipe_->wend().close(); |
|||
if (d != si.pipe_->rend().get()) |
|||
si.pipe_->rend().posix_remap(d); |
|||
break; |
|||
} |
|||
default: |
|||
{ |
|||
BOOST_ASSERT(si.type_ == stream_info::inherit); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* Configures child process' output streams. |
|||
* |
|||
* Sets up the current process' output streams to behave according to the |
|||
* information in the \a info map. \a closeflags is modified to reflect |
|||
* those descriptors that should not be closed because they where |
|||
* modified by the function. |
|||
* |
|||
* Modifies the current execution environment, so this should only be run |
|||
* on the child process after the fork(2) has happened. |
|||
* |
|||
* \throw boost::system::system_error If any error occurs during the |
|||
* configuration. |
|||
*/ |
|||
inline void setup_output(info_map &info, bool *closeflags, int maxdescs) |
|||
{ |
|||
for (info_map::iterator it = info.begin(); it != info.end(); ++it) |
|||
{ |
|||
int d = it->first; |
|||
stream_info &si = it->second; |
|||
|
|||
BOOST_ASSERT(d < maxdescs); |
|||
closeflags[d] = false; |
|||
|
|||
switch (si.type_) |
|||
{ |
|||
case stream_info::redirect: |
|||
{ |
|||
break; |
|||
} |
|||
case stream_info::use_file: |
|||
{ |
|||
int fd = ::open(si.file_.c_str(), O_WRONLY); |
|||
if (fd == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::setup_output: open(2) of " + si.file_ + " failed")); |
|||
if (fd != d) |
|||
{ |
|||
file_handle h(fd); |
|||
h.posix_remap(d); |
|||
h.release(); |
|||
} |
|||
break; |
|||
} |
|||
case stream_info::use_handle: |
|||
{ |
|||
if (si.handle_.get() != d) |
|||
si.handle_.posix_remap(d); |
|||
break; |
|||
} |
|||
case stream_info::use_pipe: |
|||
{ |
|||
si.pipe_->rend().close(); |
|||
if (d != si.pipe_->wend().get()) |
|||
si.pipe_->wend().posix_remap(d); |
|||
break; |
|||
} |
|||
default: |
|||
{ |
|||
BOOST_ASSERT(si.type_ == stream_info::inherit); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
for (info_map::const_iterator it = info.begin(); it != info.end(); ++it) |
|||
{ |
|||
int d = it->first; |
|||
const stream_info &si = it->second; |
|||
|
|||
if (si.type_ == stream_info::redirect) |
|||
file_handle::posix_dup(si.desc_to_, d).release(); |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* Starts a new child process in a POSIX operating system. |
|||
* |
|||
* This helper functions is provided to simplify the Context's task when |
|||
* it comes to starting up a new process in a POSIX operating system. |
|||
* The function hides all the details of the fork/exec pair of calls as |
|||
* well as all the setup of communication pipes and execution environment. |
|||
* |
|||
* \param exe The executable to spawn the child process. |
|||
* \param args The arguments for the executable. |
|||
* \param env The environment variables that the new child process |
|||
* receives. |
|||
* \param infoin A map describing all input file descriptors to be |
|||
* redirected. |
|||
* \param infoout A map describing all output file descriptors to be |
|||
* redirected. |
|||
* \param setup A helper object used to configure the child's execution |
|||
* environment. |
|||
* \return The new process' PID. The caller is responsible of creating |
|||
* an appropriate Child representation for it. |
|||
*/ |
|||
template <class Executable, class Arguments> |
|||
inline pid_t posix_start(const Executable &exe, const Arguments &args, const environment &env, info_map &infoin, info_map &infoout, const posix_setup &setup) |
|||
{ |
|||
pid_t pid = ::fork(); |
|||
if (pid == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_start: fork(2) failed")); |
|||
else if (pid == 0) |
|||
{ |
|||
#if defined(F_MAXFD) |
|||
int maxdescs = ::fcntl(-1, F_MAXFD, 0); |
|||
if (maxdescs == -1) |
|||
maxdescs = ::sysconf(_SC_OPEN_MAX); |
|||
#else |
|||
int maxdescs = ::sysconf(_SC_OPEN_MAX); |
|||
#endif |
|||
if (maxdescs == -1) |
|||
maxdescs = 1024; |
|||
try |
|||
{ |
|||
boost::scoped_array<bool> closeflags(new bool[maxdescs]); |
|||
for (int i = 0; i < maxdescs; ++i) |
|||
closeflags[i] = true; |
|||
|
|||
setup_input(infoin, closeflags.get(), maxdescs); |
|||
setup_output(infoout, closeflags.get(), maxdescs); |
|||
|
|||
for (int i = 0; i < maxdescs; ++i) |
|||
{ |
|||
if (closeflags[i]) |
|||
::close(i); |
|||
} |
|||
|
|||
setup(); |
|||
} |
|||
catch (const boost::system::system_error &e) |
|||
{ |
|||
::write(STDERR_FILENO, e.what(), std::strlen(e.what())); |
|||
::write(STDERR_FILENO, "\n", 1); |
|||
std::exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
std::pair<std::size_t, char**> argcv = collection_to_posix_argv(args); |
|||
char **envp = environment_to_envp(env); |
|||
|
|||
::execve(exe.c_str(), argcv.second, envp); |
|||
boost::system::system_error e(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::detail::posix_start: execve(2) failed"); |
|||
|
|||
for (std::size_t i = 0; i < argcv.first; ++i) |
|||
delete[] argcv.second[i]; |
|||
delete[] argcv.second; |
|||
|
|||
for (std::size_t i = 0; i < env.size(); ++i) |
|||
delete[] envp[i]; |
|||
delete[] envp; |
|||
|
|||
::write(STDERR_FILENO, e.what(), std::strlen(e.what())); |
|||
::write(STDERR_FILENO, "\n", 1); |
|||
std::exit(EXIT_FAILURE); |
|||
} |
|||
|
|||
BOOST_ASSERT(pid > 0); |
|||
|
|||
for (info_map::iterator it = infoin.begin(); it != infoin.end(); ++it) |
|||
{ |
|||
stream_info &si = it->second; |
|||
if (si.type_ == stream_info::use_pipe) |
|||
si.pipe_->rend().close(); |
|||
} |
|||
|
|||
for (info_map::iterator it = infoout.begin(); it != infoout.end(); ++it) |
|||
{ |
|||
stream_info &si = it->second; |
|||
if (si.type_ == stream_info::use_pipe) |
|||
si.pipe_->wend().close(); |
|||
} |
|||
|
|||
return pid; |
|||
} |
|||
|
|||
/**
|
|||
* Locates a communication pipe and returns one of its endpoints. |
|||
* |
|||
* Given a \a info map, and a file descriptor \a desc, searches for its |
|||
* communicataion pipe in the map and returns one of its endpoints as |
|||
* indicated by the \a out flag. This is intended to be used by a |
|||
* parent process after a fork(2) call. |
|||
* |
|||
* \pre If the info map contains the given descriptor, it is configured |
|||
* to use a pipe. |
|||
* \post The info map does not contain the given descriptor. |
|||
* \return If the file descriptor is found in the map, returns the pipe's |
|||
* read end if out is true; otherwise its write end. If the |
|||
* descriptor is not found returns an invalid file handle. |
|||
*/ |
|||
inline file_handle posix_info_locate_pipe(info_map &info, int desc, bool out) |
|||
{ |
|||
file_handle fh; |
|||
|
|||
info_map::iterator it = info.find(desc); |
|||
if (it != info.end()) |
|||
{ |
|||
stream_info &si = it->second; |
|||
if (si.type_ == stream_info::use_pipe) |
|||
{ |
|||
fh = out ? si.pipe_->rend().release() : si.pipe_->wend().release(); |
|||
BOOST_ASSERT(fh.valid()); |
|||
} |
|||
info.erase(it); |
|||
} |
|||
|
|||
return fh; |
|||
} |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,176 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/detail/stream_info.hpp |
|||
* |
|||
* Provides the definition of the stream_info structure. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_DETAIL_STREAM_INFO_HPP |
|||
#define BOOST_PROCESS_DETAIL_STREAM_INFO_HPP |
|||
|
|||
#include <boost/process/config.hpp> |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
# include <unistd.h> |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
#else |
|||
# error "Unsupported platform." |
|||
#endif |
|||
|
|||
#include <boost/process/stream_behavior.hpp> |
|||
#include <boost/process/detail/file_handle.hpp> |
|||
#include <boost/process/detail/pipe.hpp> |
|||
#include <boost/optional.hpp> |
|||
#include <boost/assert.hpp> |
|||
#include <string> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
namespace detail { |
|||
|
|||
/**
|
|||
* Configuration data for a file descriptor. |
|||
* |
|||
* This convenience structure provides a compact way to pass information |
|||
* around on how to configure a file descriptor. It is a lower-level |
|||
* representation of stream_behavior, as it can hold the same information |
|||
* but in a way that can be used by the underlying operating system. |
|||
*/ |
|||
struct stream_info |
|||
{ |
|||
/**
|
|||
* Supported stream types. |
|||
*/ |
|||
enum type |
|||
{ |
|||
/**
|
|||
* Matches stream_behavior::close. |
|||
*/ |
|||
close, |
|||
|
|||
/**
|
|||
* Matches stream_behavior::inherit. |
|||
*/ |
|||
inherit, |
|||
|
|||
/**
|
|||
* Matches stream_behavior::redirect_to_stdout and |
|||
* stream_behavior::posix_redirect. |
|||
*/ |
|||
redirect, |
|||
|
|||
/**
|
|||
* Matches stream_behavior::silence. |
|||
*/ |
|||
use_file, |
|||
|
|||
/**
|
|||
* TODO: Matches nothing yet ... |
|||
*/ |
|||
use_handle, |
|||
|
|||
/**
|
|||
* Matches stream_behavior::capture. |
|||
*/ |
|||
use_pipe |
|||
}; |
|||
|
|||
/**
|
|||
* Stream type. |
|||
*/ |
|||
type type_; |
|||
|
|||
/**
|
|||
* Descriptor to use when stream type is set to \a redirect. |
|||
*/ |
|||
int desc_to_; |
|||
|
|||
/**
|
|||
* File to use when stream type is set to \a use_file. |
|||
*/ |
|||
std::string file_; |
|||
|
|||
/**
|
|||
* Handle to use when stream type is set to \a use_handle. |
|||
*/ |
|||
file_handle handle_; |
|||
|
|||
/**
|
|||
* Pipe to use when stream type is set to \a use_pipe. |
|||
*/ |
|||
boost::optional<pipe> pipe_; |
|||
|
|||
/**
|
|||
* Constructs a new stream_info object. |
|||
*/ |
|||
stream_info(const stream_behavior &sb, bool out) |
|||
{ |
|||
switch (sb.type_) |
|||
{ |
|||
case stream_behavior::close: |
|||
{ |
|||
type_ = close; |
|||
break; |
|||
} |
|||
case stream_behavior::inherit: |
|||
{ |
|||
type_ = inherit; |
|||
break; |
|||
} |
|||
case stream_behavior::redirect_to_stdout: |
|||
{ |
|||
type_ = redirect; |
|||
#if defined(BOOST_POSIX_API) |
|||
desc_to_ = STDOUT_FILENO; |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
desc_to_ = 1; |
|||
#endif |
|||
break; |
|||
} |
|||
#if defined(BOOST_POSIX_API) |
|||
case stream_behavior::posix_redirect: |
|||
{ |
|||
type_ = redirect; |
|||
desc_to_ = sb.desc_to_; |
|||
break; |
|||
} |
|||
#endif |
|||
case stream_behavior::silence: |
|||
{ |
|||
type_ = use_file; |
|||
#if defined(BOOST_POSIX_API) |
|||
file_ = out ? "/dev/null" : "/dev/zero"; |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
file_ = "NUL"; |
|||
#endif |
|||
break; |
|||
} |
|||
case stream_behavior::capture: |
|||
{ |
|||
type_ = use_pipe; |
|||
pipe_ = pipe(); |
|||
break; |
|||
} |
|||
default: |
|||
{ |
|||
BOOST_ASSERT(false); |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,231 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/detail/systembuf.hpp |
|||
* |
|||
* Includes the declaration of the systembuf class. This file is for |
|||
* internal usage only and must not be included by the library user. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP |
|||
#define BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP |
|||
|
|||
#include <boost/process/config.hpp> |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
# include <sys/types.h> |
|||
# include <unistd.h> |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
# include <windows.h> |
|||
#else |
|||
# error "Unsupported platform." |
|||
#endif |
|||
|
|||
#include <boost/noncopyable.hpp> |
|||
#include <boost/scoped_array.hpp> |
|||
#include <boost/assert.hpp> |
|||
#include <streambuf> |
|||
#include <cstddef> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
class postream; |
|||
|
|||
namespace detail { |
|||
|
|||
/**
|
|||
* std::streambuf implementation for system file handles. |
|||
* |
|||
* systembuf provides a std::streambuf implementation for system file |
|||
* handles. Contrarywise to file_handle, this class does \b not take |
|||
* ownership of the native file handle; this should be taken care of |
|||
* somewhere else. |
|||
* |
|||
* This class follows the expected semantics of a std::streambuf object. |
|||
* However, it is not copyable to avoid introducing inconsistences with |
|||
* the on-disk file and the in-memory buffers. |
|||
*/ |
|||
class systembuf : public std::streambuf, public boost::noncopyable |
|||
{ |
|||
friend class ::boost::process::postream; |
|||
|
|||
public: |
|||
#if defined(BOOST_PROCESS_DOXYGEN) |
|||
/**
|
|||
* Opaque name for the native handle type. |
|||
*/ |
|||
typedef NativeHandleType handle_type; |
|||
#elif defined(BOOST_POSIX_API) |
|||
typedef int handle_type; |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
typedef HANDLE handle_type; |
|||
#endif |
|||
|
|||
/**
|
|||
* Constructs a new systembuf for the given file handle. |
|||
* |
|||
* This constructor creates a new systembuf object that reads or |
|||
* writes data from/to the \a h native file handle. This handle |
|||
* is \b not owned by the created systembuf object; the code |
|||
* should take care of it externally. |
|||
* |
|||
* This class buffers input and output; the buffer size may be |
|||
* tuned through the \a bufsize parameter, which defaults to 8192 |
|||
* bytes. |
|||
* |
|||
* \see pistream and postream |
|||
*/ |
|||
explicit systembuf(handle_type h, std::size_t bufsize = 8192) |
|||
: handle_(h), |
|||
bufsize_(bufsize), |
|||
read_buf_(new char[bufsize]), |
|||
write_buf_(new char[bufsize]) |
|||
{ |
|||
#if defined(BOOST_POSIX_API) |
|||
BOOST_ASSERT(handle_ >= 0); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
BOOST_ASSERT(handle_ != INVALID_HANDLE_VALUE); |
|||
#endif |
|||
BOOST_ASSERT(bufsize_ > 0); |
|||
|
|||
setp(write_buf_.get(), write_buf_.get() + bufsize_); |
|||
} |
|||
|
|||
protected: |
|||
/**
|
|||
* Reads new data from the native file handle. |
|||
* |
|||
* This operation is called by input methods when there is no more |
|||
* data in the input buffer. The function fills the buffer with new |
|||
* data, if available. |
|||
* |
|||
* \pre All input positions are exhausted (gptr() >= egptr()). |
|||
* \post The input buffer has new data, if available. |
|||
* \returns traits_type::eof() if a read error occurrs or there are |
|||
* no more data to be read. Otherwise returns |
|||
* traits_type::to_int_type(*gptr()). |
|||
*/ |
|||
virtual int_type underflow() |
|||
{ |
|||
BOOST_ASSERT(gptr() >= egptr()); |
|||
|
|||
bool ok; |
|||
#if defined(BOOST_POSIX_API) |
|||
ssize_t cnt = ::read(handle_, read_buf_.get(), bufsize_); |
|||
ok = (cnt != -1 && cnt != 0); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
DWORD cnt; |
|||
BOOL res = ::ReadFile(handle_, read_buf_.get(), bufsize_, &cnt, NULL); |
|||
ok = (res && cnt > 0); |
|||
#endif |
|||
|
|||
if (!ok) |
|||
return traits_type::eof(); |
|||
else |
|||
{ |
|||
setg(read_buf_.get(), read_buf_.get(), read_buf_.get() + cnt); |
|||
return traits_type::to_int_type(*gptr()); |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* Makes room in the write buffer for additional data. |
|||
* |
|||
* This operation is called by output methods when there is no more |
|||
* space in the output buffer to hold a new element. The function |
|||
* first flushes the buffer's contents to disk and then clears it to |
|||
* leave room for more characters. The given \a c character is |
|||
* stored at the beginning of the new space. |
|||
* |
|||
* \pre All output positions are exhausted (pptr() >= epptr()). |
|||
* \post The output buffer has more space if no errors occurred |
|||
* during the write to disk. |
|||
* \post *(pptr() - 1) is \a c. |
|||
* \returns traits_type::eof() if a write error occurrs. Otherwise |
|||
* returns traits_type::not_eof(c). |
|||
*/ |
|||
virtual int_type overflow(int c) |
|||
{ |
|||
BOOST_ASSERT(pptr() >= epptr()); |
|||
|
|||
if (sync() == -1) |
|||
return traits_type::eof(); |
|||
|
|||
if (!traits_type::eq_int_type(c, traits_type::eof())) |
|||
{ |
|||
traits_type::assign(*pptr(), c); |
|||
pbump(1); |
|||
} |
|||
|
|||
return traits_type::not_eof(c); |
|||
} |
|||
|
|||
/**
|
|||
* Flushes the output buffer to disk. |
|||
* |
|||
* Synchronizes the systembuf buffers with the contents of the file |
|||
* associated to this object through the native file handle. The |
|||
* output buffer is flushed to disk and cleared to leave new room |
|||
* for more data. |
|||
* |
|||
* \returns 0 on success, -1 if an error occurred. |
|||
*/ |
|||
virtual int sync() |
|||
{ |
|||
#if defined(BOOST_POSIX_API) |
|||
ssize_t cnt = pptr() - pbase(); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
long cnt = pptr() - pbase(); |
|||
#endif |
|||
|
|||
bool ok; |
|||
#if defined(BOOST_POSIX_API) |
|||
ok = ::write(handle_, pbase(), cnt) == cnt; |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
DWORD rcnt; |
|||
BOOL res = ::WriteFile(handle_, pbase(), cnt, &rcnt, NULL); |
|||
ok = (res && static_cast<long>(rcnt) == cnt); |
|||
#endif |
|||
|
|||
if (ok) |
|||
pbump(-cnt); |
|||
return ok ? 0 : -1; |
|||
} |
|||
|
|||
private: |
|||
/**
|
|||
* Native file handle used by the systembuf object. |
|||
*/ |
|||
handle_type handle_; |
|||
|
|||
/**
|
|||
* Internal buffer size used during read and write operations. |
|||
*/ |
|||
std::size_t bufsize_; |
|||
|
|||
/**
|
|||
* Internal buffer used during read operations. |
|||
*/ |
|||
boost::scoped_array<char> read_buf_; |
|||
|
|||
/**
|
|||
* Internal buffer used during write operations. |
|||
*/ |
|||
boost::scoped_array<char> write_buf_; |
|||
}; |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,355 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/detail/win32_ops.hpp |
|||
* |
|||
* Provides some convenience functions to start processes under |
|||
* Windows-compatible operating systems. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_DETAIL_WIN32_OPS_HPP |
|||
#define BOOST_PROCESS_DETAIL_WIN32_OPS_HPP |
|||
|
|||
#include <boost/process/environment.hpp> |
|||
#include <boost/process/detail/file_handle.hpp> |
|||
#include <boost/process/detail/pipe.hpp> |
|||
#include <boost/process/detail/stream_info.hpp> |
|||
#include <boost/scoped_ptr.hpp> |
|||
#include <boost/shared_array.hpp> |
|||
#include <boost/scoped_array.hpp> |
|||
#include <boost/assert.hpp> |
|||
#include <boost/system/system_error.hpp> |
|||
#include <boost/throw_exception.hpp> |
|||
#include <vector> |
|||
#include <string> |
|||
#include <cstddef> |
|||
#include <string.h> |
|||
#include <windows.h> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
namespace detail { |
|||
|
|||
/**
|
|||
* Converts the command line to a plain string. Converts the command line's |
|||
* list of arguments to the format expected by the \a lpCommandLine parameter |
|||
* in the CreateProcess() system call. |
|||
* |
|||
* This operation is only available on Windows systems. |
|||
* |
|||
* \return A dynamically allocated string holding the command line |
|||
* to be passed to the executable. It is returned in a |
|||
* shared_array object to ensure its release at some point. |
|||
*/ |
|||
template <class Arguments> |
|||
inline boost::shared_array<char> collection_to_win32_cmdline(const Arguments &args) |
|||
{ |
|||
typedef std::vector<std::string> arguments_t; |
|||
arguments_t args2; |
|||
typename Arguments::size_type i = 0; |
|||
std::size_t size = 0; |
|||
for (typename Arguments::const_iterator it = args.begin(); it != args.end(); ++it) |
|||
{ |
|||
std::string arg = *it; |
|||
|
|||
std::string::size_type pos = 0; |
|||
while ( (pos = arg.find('"', pos)) != std::string::npos) |
|||
{ |
|||
arg.replace(pos, 1, "\\\""); |
|||
pos += 2; |
|||
} |
|||
|
|||
if (arg.find(' ') != std::string::npos) |
|||
arg = '\"' + arg + '\"'; |
|||
|
|||
if (i++ != args.size() - 1) |
|||
arg += ' '; |
|||
|
|||
args2.push_back(arg); |
|||
size += arg.size() + 1; |
|||
} |
|||
|
|||
boost::shared_array<char> cmdline(new char[size]); |
|||
cmdline.get()[0] = '\0'; |
|||
for (arguments_t::size_type i = 0; i < args.size(); ++i) |
|||
#if defined(__CYGWIN__) |
|||
::strncat(cmdline.get(), args2[i].c_str(), args2[i].size()); |
|||
#else |
|||
::strcat_s(cmdline.get(), size, args2[i].c_str()); |
|||
#endif |
|||
|
|||
return cmdline; |
|||
} |
|||
|
|||
/**
|
|||
* Converts an environment to a string used by CreateProcess(). |
|||
* |
|||
* Converts the environment's contents to the format used by the |
|||
* CreateProcess() system call. The returned char* string is |
|||
* allocated in dynamic memory; the caller must free it when not |
|||
* used any more. This is enforced by the use of a shared pointer. |
|||
* |
|||
* \return A dynamically allocated char* string that represents |
|||
* the environment's content. This string is of the form |
|||
* var1=value1\\0var2=value2\\0\\0. |
|||
*/ |
|||
inline boost::shared_array<char> environment_to_win32_strings(const environment &env) |
|||
{ |
|||
boost::shared_array<char> envp; |
|||
|
|||
if (env.empty()) |
|||
{ |
|||
envp.reset(new char[2]); |
|||
::ZeroMemory(envp.get(), 2); |
|||
} |
|||
else |
|||
{ |
|||
std::string s; |
|||
for (environment::const_iterator it = env.begin(); it != env.end(); ++it) |
|||
{ |
|||
s += it->first + "=" + it->second; |
|||
s.push_back(0); |
|||
} |
|||
|
|||
envp.reset(new char[s.size() + 1]); |
|||
#if defined(__CYGWIN__) |
|||
::memcpy(envp.get(), s.c_str(), s.size() + 1); |
|||
#else |
|||
::memcpy_s(envp.get(), s.size() + 1, s.c_str(), s.size() + 1); |
|||
#endif |
|||
} |
|||
|
|||
return envp; |
|||
} |
|||
|
|||
/**
|
|||
* Helper class to configure a Win32 %child. |
|||
* |
|||
* This helper class is used to hold all the attributes that configure a |
|||
* new Win32 %child process. |
|||
* |
|||
* All its fields are public for simplicity. It is only intended for |
|||
* internal use and it is heavily coupled with the Context |
|||
* implementations. |
|||
*/ |
|||
struct win32_setup |
|||
{ |
|||
/**
|
|||
* The work directory. |
|||
* |
|||
* This string specifies the directory in which the %child process |
|||
* starts execution. It cannot be empty. |
|||
*/ |
|||
std::string work_directory; |
|||
|
|||
/**
|
|||
* The process startup properties. |
|||
* |
|||
* This Win32-specific object holds a list of properties that describe |
|||
* how the new process should be started. The \a STARTF_USESTDHANDLES |
|||
* flag should not be set in it because it is automatically configured |
|||
* by win32_start(). |
|||
*/ |
|||
STARTUPINFOA *startupinfo; |
|||
}; |
|||
|
|||
/**
|
|||
* Starts a new child process in a Win32 operating system. |
|||
* |
|||
* This helper functions is provided to simplify the Context's task when |
|||
* it comes to starting up a new process in a Win32 operating system. |
|||
* |
|||
* \param exe The executable to spawn the child process. |
|||
* \param args The arguments for the executable. |
|||
* \param env The environment variables that the new child process |
|||
* receives. |
|||
* \param infoin Information that describes stdin's behavior. |
|||
* \param infoout Information that describes stdout's behavior. |
|||
* \param infoerr Information that describes stderr's behavior. |
|||
* \param setup A helper object holding extra child information. |
|||
* \return The new process' information as returned by the CreateProcess() |
|||
* system call. The caller is responsible of creating an |
|||
* appropriate Child representation for it. |
|||
* \pre \a setup.startupinfo_ cannot have the \a STARTF_USESTDHANDLES set |
|||
* in the \a dwFlags field. |
|||
*/ |
|||
template <class Executable, class Arguments> |
|||
inline PROCESS_INFORMATION win32_start(const Executable &exe, const Arguments &args, const environment &env, stream_info &infoin, stream_info &infoout, stream_info &infoerr, const win32_setup &setup) |
|||
{ |
|||
file_handle chin, chout, cherr; |
|||
|
|||
BOOST_ASSERT(setup.startupinfo->cb >= sizeof(STARTUPINFOA)); |
|||
BOOST_ASSERT(!(setup.startupinfo->dwFlags & STARTF_USESTDHANDLES)); |
|||
|
|||
boost::scoped_ptr<STARTUPINFOA> si(new STARTUPINFOA); |
|||
::CopyMemory(si.get(), setup.startupinfo, sizeof(*setup.startupinfo)); |
|||
si->dwFlags |= STARTF_USESTDHANDLES; |
|||
|
|||
switch (infoin.type_) |
|||
{ |
|||
case stream_info::close: |
|||
{ |
|||
break; |
|||
} |
|||
case stream_info::inherit: |
|||
{ |
|||
chin = file_handle::win32_std(STD_INPUT_HANDLE, true); |
|||
break; |
|||
} |
|||
case stream_info::use_file: |
|||
{ |
|||
HANDLE h = ::CreateFileA(infoin.file_.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
|||
if (h == INVALID_HANDLE_VALUE) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed")); |
|||
chin = file_handle(h); |
|||
break; |
|||
} |
|||
case stream_info::use_handle: |
|||
{ |
|||
chin = infoin.handle_; |
|||
chin.win32_set_inheritable(true); |
|||
break; |
|||
} |
|||
case stream_info::use_pipe: |
|||
{ |
|||
infoin.pipe_->rend().win32_set_inheritable(true); |
|||
chin = infoin.pipe_->rend(); |
|||
break; |
|||
} |
|||
default: |
|||
{ |
|||
BOOST_ASSERT(false); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
si->hStdInput = chin.valid() ? chin.get() : INVALID_HANDLE_VALUE; |
|||
|
|||
switch (infoout.type_) |
|||
{ |
|||
case stream_info::close: |
|||
{ |
|||
break; |
|||
} |
|||
case stream_info::inherit: |
|||
{ |
|||
chout = file_handle::win32_std(STD_OUTPUT_HANDLE, true); |
|||
break; |
|||
} |
|||
case stream_info::use_file: |
|||
{ |
|||
HANDLE h = ::CreateFileA(infoout.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
|||
if (h == INVALID_HANDLE_VALUE) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed")); |
|||
chout = file_handle(h); |
|||
break; |
|||
} |
|||
case stream_info::use_handle: |
|||
{ |
|||
chout = infoout.handle_; |
|||
chout.win32_set_inheritable(true); |
|||
break; |
|||
} |
|||
case stream_info::use_pipe: |
|||
{ |
|||
infoout.pipe_->wend().win32_set_inheritable(true); |
|||
chout = infoout.pipe_->wend(); |
|||
break; |
|||
} |
|||
default: |
|||
{ |
|||
BOOST_ASSERT(false); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
si->hStdOutput = chout.valid() ? chout.get() : INVALID_HANDLE_VALUE; |
|||
|
|||
switch (infoerr.type_) |
|||
{ |
|||
case stream_info::close: |
|||
{ |
|||
break; |
|||
} |
|||
case stream_info::inherit: |
|||
{ |
|||
cherr = file_handle::win32_std(STD_ERROR_HANDLE, true); |
|||
break; |
|||
} |
|||
case stream_info::redirect: |
|||
{ |
|||
BOOST_ASSERT(infoerr.desc_to_ == 1); |
|||
BOOST_ASSERT(chout.valid()); |
|||
cherr = file_handle::win32_dup(chout.get(), true); |
|||
break; |
|||
} |
|||
case stream_info::use_file: |
|||
{ |
|||
HANDLE h = ::CreateFileA(infoerr.file_.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
|||
if (h == INVALID_HANDLE_VALUE) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateFile failed")); |
|||
cherr = file_handle(h); |
|||
break; |
|||
} |
|||
case stream_info::use_handle: |
|||
{ |
|||
cherr = infoerr.handle_; |
|||
cherr.win32_set_inheritable(true); |
|||
break; |
|||
} |
|||
case stream_info::use_pipe: |
|||
{ |
|||
infoerr.pipe_->wend().win32_set_inheritable(true); |
|||
cherr = infoerr.pipe_->wend(); |
|||
break; |
|||
} |
|||
default: |
|||
{ |
|||
BOOST_ASSERT(false); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
si->hStdError = cherr.valid() ? cherr.get() : INVALID_HANDLE_VALUE; |
|||
|
|||
PROCESS_INFORMATION pi; |
|||
::ZeroMemory(&pi, sizeof(pi)); |
|||
|
|||
boost::shared_array<char> cmdline = collection_to_win32_cmdline(args); |
|||
|
|||
boost::scoped_array<char> executable(new char[exe.size() + 1]); |
|||
#if defined(__CYGWIN__) |
|||
::strcpy(executable.get(), exe.c_str()); |
|||
#else |
|||
::strcpy_s(executable.get(), exe.size() + 1, exe.c_str()); |
|||
#endif |
|||
|
|||
boost::scoped_array<char> workdir(new char[setup.work_directory.size() + 1]); |
|||
#if defined(__CYGWIN__) |
|||
::strcpy(workdir.get(), setup.work_directory.c_str()); |
|||
#else |
|||
::strcpy_s(workdir.get(), setup.work_directory.size() + 1, setup.work_directory.c_str()); |
|||
#endif |
|||
|
|||
boost::shared_array<char> envstrs = environment_to_win32_strings(env); |
|||
|
|||
if (!::CreateProcessA(executable.get()[0] ? executable.get() : NULL, cmdline.get(), NULL, NULL, TRUE, CREATE_NO_WINDOW, envstrs.get(), workdir.get(), si.get(), &pi)) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::detail::win32_start: CreateProcess failed")); |
|||
|
|||
return pi; |
|||
} |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,50 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/environment.hpp |
|||
* |
|||
* Includes the declaration of the environment class. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_ENVIRONMENT_HPP |
|||
#define BOOST_PROCESS_ENVIRONMENT_HPP |
|||
|
|||
#include <string> |
|||
#include <map> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Representation of a process' environment variables. |
|||
* |
|||
* The environment is a map that stablishes an unidirectional |
|||
* association between variable names and their values and is |
|||
* represented by a string to string map. |
|||
* |
|||
* Variables may be defined to the empty string. Be aware that doing so |
|||
* is not portable: POSIX systems will treat such variables as being |
|||
* defined to the empty value, but Windows systems are not able to |
|||
* distinguish them from undefined variables. |
|||
* |
|||
* Neither POSIX nor Windows systems support a variable with no name. |
|||
* |
|||
* It is worthy to note that the environment is sorted alphabetically. |
|||
* This is provided for-free by the map container used to implement this |
|||
* type, and this behavior is required by Windows systems. |
|||
*/ |
|||
typedef std::map<std::string, std::string> environment; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,583 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/operations.hpp |
|||
* |
|||
* Provides miscellaneous free functions. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_OPERATIONS_HPP |
|||
#define BOOST_PROCESS_OPERATIONS_HPP |
|||
|
|||
#include <boost/process/config.hpp> |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
# include <boost/process/detail/posix_ops.hpp> |
|||
# include <stdlib.h> |
|||
# include <unistd.h> |
|||
# if defined(__CYGWIN__) |
|||
# include <boost/scoped_array.hpp> |
|||
# include <sys/cygwin.h> |
|||
# endif |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
# include <boost/process/detail/win32_ops.hpp> |
|||
# include <boost/algorithm/string/predicate.hpp> |
|||
# include <windows.h> |
|||
#else |
|||
# error "Unsupported platform." |
|||
#endif |
|||
|
|||
#include <boost/process/child.hpp> |
|||
#include <boost/process/stream_behavior.hpp> |
|||
#include <boost/process/status.hpp> |
|||
#include <boost/process/detail/file_handle.hpp> |
|||
#include <boost/process/detail/pipe.hpp> |
|||
#include <boost/process/detail/stream_info.hpp> |
|||
#include <boost/filesystem/path.hpp> |
|||
#include <boost/algorithm/string/predicate.hpp> |
|||
#include <boost/system/system_error.hpp> |
|||
#include <boost/throw_exception.hpp> |
|||
#include <boost/scoped_array.hpp> |
|||
#include <boost/assert.hpp> |
|||
#include <string> |
|||
#include <vector> |
|||
#include <stdexcept> |
|||
#include <cstddef> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Locates the executable program \a file in all the directory components |
|||
* specified in \a path. If \a path is empty, the value of the PATH |
|||
* environment variable is used. |
|||
* |
|||
* The path variable is interpreted following the same conventions used |
|||
* to parse the PATH environment variable in the underlying platform. |
|||
* |
|||
* \throw boost::filesystem::filesystem_error If the file cannot be found |
|||
* in the path. |
|||
*/ |
|||
inline std::string find_executable_in_path(const std::string &file, std::string path = "") |
|||
{ |
|||
#if defined(BOOST_POSIX_API) |
|||
BOOST_ASSERT(file.find('/') == std::string::npos); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
BOOST_ASSERT(file.find_first_of("\\/") == std::string::npos); |
|||
#endif |
|||
|
|||
std::string result; |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
if (path.empty()) |
|||
{ |
|||
const char *envpath = ::getenv("PATH"); |
|||
// if (!envpath)
|
|||
// boost::throw_exception(boost::filesystem::filesystem_error("boost::process::find_executable_in_path: retrieving PATH failed", file, boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory)));
|
|||
|
|||
path = envpath; |
|||
} |
|||
BOOST_ASSERT(!path.empty()); |
|||
|
|||
#if defined(__CYGWIN__) |
|||
if (!::cygwin_posix_path_list_p(path.c_str())) |
|||
{ |
|||
int size = ::cygwin_win32_to_posix_path_list_buf_size(path.c_str()); |
|||
boost::scoped_array<char> cygpath(new char[size]); |
|||
::cygwin_win32_to_posix_path_list(path.c_str(), cygpath.get()); |
|||
path = cygpath.get(); |
|||
} |
|||
#endif |
|||
|
|||
std::string::size_type pos1 = 0, pos2; |
|||
do |
|||
{ |
|||
pos2 = path.find(':', pos1); |
|||
std::string dir = (pos2 != std::string::npos) ? path.substr(pos1, pos2 - pos1) : path.substr(pos1); |
|||
std::string f = dir + (boost::algorithm::ends_with(dir, "/") ? "" : "/") + file; |
|||
if (!::access(f.c_str(), X_OK)) |
|||
result = f; |
|||
pos1 = pos2 + 1; |
|||
} while (pos2 != std::string::npos && result.empty()); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
const char *exts[] = { "", ".exe", ".com", ".bat", NULL }; |
|||
const char **ext = exts; |
|||
while (*ext) |
|||
{ |
|||
char buf[MAX_PATH]; |
|||
char *dummy; |
|||
DWORD size = ::SearchPathA(path.empty() ? NULL : path.c_str(), file.c_str(), *ext, MAX_PATH, buf, &dummy); |
|||
BOOST_ASSERT(size < MAX_PATH); |
|||
if (size > 0) |
|||
{ |
|||
result = buf; |
|||
break; |
|||
} |
|||
++ext; |
|||
} |
|||
#endif |
|||
|
|||
// if (result.empty())
|
|||
// boost::throw_exception(boost::filesystem::filesystem_error("boost::process::find_executable_in_path: file not found", file, boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory)));
|
|||
|
|||
return result; |
|||
} |
|||
|
|||
/**
|
|||
* Extracts the program name from a given executable. |
|||
* |
|||
* \return The program name. On Windows the program name |
|||
* is returned without a file extension. |
|||
*/ |
|||
inline std::string executable_to_progname(const std::string &exe) |
|||
{ |
|||
std::string::size_type begin = 0; |
|||
std::string::size_type end = std::string::npos; |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
std::string::size_type slash = exe.rfind('/'); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
std::string::size_type slash = exe.find_last_of("/\\"); |
|||
#endif |
|||
if (slash != std::string::npos) |
|||
begin = slash + 1; |
|||
|
|||
#if defined(BOOST_WINDOWS_API) |
|||
if (exe.size() > 4 && |
|||
(boost::algorithm::iends_with(exe, ".exe") || boost::algorithm::iends_with(exe, ".com") || boost::algorithm::iends_with(exe, ".bat"))) |
|||
end = exe.size() - 4; |
|||
#endif |
|||
|
|||
return exe.substr(begin, end - begin); |
|||
} |
|||
|
|||
/**
|
|||
* Starts a new child process. |
|||
* |
|||
* Launches a new process based on the binary image specified by the |
|||
* executable, the set of arguments to be passed to it and several |
|||
* parameters that describe the execution context. |
|||
* |
|||
* \remark Blocking remarks: This function may block if the device |
|||
* holding the executable blocks when loading the image. This might |
|||
* happen if, e.g., the binary is being loaded from a network share. |
|||
* |
|||
* \return A handle to the new child process. |
|||
*/ |
|||
template <class Executable, class Arguments, class Context> |
|||
inline child launch(const Executable &exe, const Arguments &args, const Context &ctx) |
|||
{ |
|||
detail::file_handle fhstdin, fhstdout, fhstderr; |
|||
|
|||
BOOST_ASSERT(!args.empty()); |
|||
BOOST_ASSERT(!ctx.work_directory.empty()); |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
detail::info_map infoin, infoout; |
|||
|
|||
if (ctx.stdin_behavior.get_type() != stream_behavior::close) |
|||
{ |
|||
detail::stream_info si = detail::stream_info(ctx.stdin_behavior, false); |
|||
infoin.insert(detail::info_map::value_type(STDIN_FILENO, si)); |
|||
} |
|||
|
|||
if (ctx.stdout_behavior.get_type() != stream_behavior::close) |
|||
{ |
|||
detail::stream_info si = detail::stream_info(ctx.stdout_behavior, true); |
|||
infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si)); |
|||
} |
|||
|
|||
if (ctx.stderr_behavior.get_type() != stream_behavior::close) |
|||
{ |
|||
detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true); |
|||
infoout.insert(detail::info_map::value_type(STDERR_FILENO, si)); |
|||
} |
|||
|
|||
detail::posix_setup s; |
|||
s.work_directory = ctx.work_directory; |
|||
|
|||
child::id_type pid = detail::posix_start(exe, args, ctx.environment, infoin, infoout, s); |
|||
|
|||
if (ctx.stdin_behavior.get_type() == stream_behavior::capture) |
|||
{ |
|||
fhstdin = detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false); |
|||
BOOST_ASSERT(fhstdin.valid()); |
|||
} |
|||
|
|||
if (ctx.stdout_behavior.get_type() == stream_behavior::capture) |
|||
{ |
|||
fhstdout = detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true); |
|||
BOOST_ASSERT(fhstdout.valid()); |
|||
} |
|||
|
|||
if (ctx.stderr_behavior.get_type() == stream_behavior::capture) |
|||
{ |
|||
fhstderr = detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true); |
|||
BOOST_ASSERT(fhstderr.valid()); |
|||
} |
|||
|
|||
return child(pid, fhstdin, fhstdout, fhstderr); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
detail::stream_info behin = detail::stream_info(ctx.stdin_behavior, false); |
|||
if (behin.type_ == detail::stream_info::use_pipe) |
|||
fhstdin = behin.pipe_->wend(); |
|||
detail::stream_info behout = detail::stream_info(ctx.stdout_behavior, true); |
|||
if (behout.type_ == detail::stream_info::use_pipe) |
|||
fhstdout = behout.pipe_->rend(); |
|||
detail::stream_info beherr = detail::stream_info(ctx.stderr_behavior, true); |
|||
if (beherr.type_ == detail::stream_info::use_pipe) |
|||
fhstderr = beherr.pipe_->rend(); |
|||
|
|||
STARTUPINFOA si; |
|||
::ZeroMemory(&si, sizeof(si)); |
|||
si.cb = sizeof(si); |
|||
|
|||
detail::win32_setup s; |
|||
s.work_directory = ctx.work_directory; |
|||
s.startupinfo = &si; |
|||
|
|||
PROCESS_INFORMATION pi = detail::win32_start(exe, args, ctx.environment, behin, behout, beherr, s); |
|||
|
|||
if (!::CloseHandle(pi.hThread)) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch: CloseHandle failed")); |
|||
|
|||
return child(pi.dwProcessId, fhstdin, fhstdout, fhstderr, detail::file_handle(pi.hProcess)); |
|||
#endif |
|||
} |
|||
|
|||
/**
|
|||
* Launches a shell-based command. |
|||
* |
|||
* Executes the given command through the default system shell. The |
|||
* command is subject to pattern expansion, redirection and pipelining. |
|||
* The shell is launched as described by the parameters in the execution |
|||
* context. |
|||
* |
|||
* This function behaves similarly to the system(3) system call. In a |
|||
* POSIX system, the command is fed to /bin/sh whereas under a Windows |
|||
* system, it is fed to cmd.exe. It is difficult to write portable |
|||
* commands as the first parameter, but this function comes in handy in |
|||
* multiple situations. |
|||
*/ |
|||
template <class Context> |
|||
inline child launch_shell(const std::string &command, const Context &ctx) |
|||
{ |
|||
std::string exe; |
|||
std::vector<std::string> args; |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
exe = "/bin/sh"; |
|||
args.push_back("sh"); |
|||
args.push_back("-c"); |
|||
args.push_back(command); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
char sysdir[MAX_PATH]; |
|||
UINT size = ::GetSystemDirectoryA(sysdir, sizeof(sysdir)); |
|||
if (!size) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_shell: GetWindowsDirectory failed")); |
|||
BOOST_ASSERT(size < MAX_PATH); |
|||
|
|||
exe = std::string(sysdir) + (sysdir[size - 1] != '\\' ? "\\cmd.exe" : "cmd.exe"); |
|||
args.push_back("cmd"); |
|||
args.push_back("/c"); |
|||
args.push_back(command); |
|||
#endif |
|||
|
|||
return launch(exe, args, ctx); |
|||
} |
|||
|
|||
/**
|
|||
* Launches a pipelined set of child processes. |
|||
* |
|||
* Given a collection of pipeline_entry objects describing how to launch |
|||
* a set of child processes, spawns them all and connects their inputs and |
|||
* outputs in a way that permits pipelined communication. |
|||
* |
|||
* \pre Let 1..N be the processes in the collection: the input behavior of |
|||
* the 2..N processes must be set to close_stream(). |
|||
* \pre Let 1..N be the processes in the collection: the output behavior of |
|||
* the 1..N-1 processes must be set to close_stream(). |
|||
* \remark Blocking remarks: This function may block if the device holding |
|||
* the executable of one of the entries blocks when loading the |
|||
* image. This might happen if, e.g., the binary is being loaded |
|||
* from a network share. |
|||
* \return A set of Child objects that represent all the processes spawned |
|||
* by this call. You should use wait_children() to wait for their |
|||
* termination. |
|||
*/ |
|||
template <class Entries> |
|||
inline children launch_pipeline(const Entries &entries) |
|||
{ |
|||
BOOST_ASSERT(entries.size() >= 2); |
|||
|
|||
children cs; |
|||
detail::file_handle fhinvalid; |
|||
|
|||
boost::scoped_array<detail::pipe> pipes(new detail::pipe[entries.size() - 1]); |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
{ |
|||
typename Entries::size_type i = 0; |
|||
const typename Entries::value_type::context_type &ctx = entries[i].context; |
|||
|
|||
detail::info_map infoin, infoout; |
|||
|
|||
if (ctx.stdin_behavior.get_type() != stream_behavior::close) |
|||
{ |
|||
detail::stream_info si = detail::stream_info(ctx.stdin_behavior, false); |
|||
infoin.insert(detail::info_map::value_type(STDIN_FILENO, si)); |
|||
} |
|||
|
|||
BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close); |
|||
detail::stream_info si2(close_stream(), true); |
|||
si2.type_ = detail::stream_info::use_handle; |
|||
si2.handle_ = pipes[i].wend().release(); |
|||
infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si2)); |
|||
|
|||
if (ctx.stderr_behavior.get_type() != stream_behavior::close) |
|||
{ |
|||
detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true); |
|||
infoout.insert(detail::info_map::value_type(STDERR_FILENO, si)); |
|||
} |
|||
|
|||
detail::posix_setup s; |
|||
s.work_directory = ctx.work_directory; |
|||
|
|||
pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s); |
|||
|
|||
detail::file_handle fhstdin; |
|||
|
|||
if (ctx.stdin_behavior.get_type() == stream_behavior::capture) |
|||
{ |
|||
fhstdin = detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false); |
|||
BOOST_ASSERT(fhstdin.valid()); |
|||
} |
|||
|
|||
cs.push_back(child(pid, fhstdin, fhinvalid, fhinvalid)); |
|||
} |
|||
|
|||
for (typename Entries::size_type i = 1; i < entries.size() - 1; ++i) |
|||
{ |
|||
const typename Entries::value_type::context_type &ctx = entries[i].context; |
|||
detail::info_map infoin, infoout; |
|||
|
|||
BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close); |
|||
detail::stream_info si1(close_stream(), false); |
|||
si1.type_ = detail::stream_info::use_handle; |
|||
si1.handle_ = pipes[i - 1].rend().release(); |
|||
infoin.insert(detail::info_map::value_type(STDIN_FILENO, si1)); |
|||
|
|||
BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close); |
|||
detail::stream_info si2(close_stream(), true); |
|||
si2.type_ = detail::stream_info::use_handle; |
|||
si2.handle_ = pipes[i].wend().release(); |
|||
infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si2)); |
|||
|
|||
if (ctx.stderr_behavior.get_type() != stream_behavior::close) |
|||
{ |
|||
detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true); |
|||
infoout.insert(detail::info_map::value_type(STDERR_FILENO, si)); |
|||
} |
|||
|
|||
detail::posix_setup s; |
|||
s.work_directory = ctx.work_directory; |
|||
|
|||
pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s); |
|||
|
|||
cs.push_back(child(pid, fhinvalid, fhinvalid, fhinvalid)); |
|||
} |
|||
|
|||
{ |
|||
typename Entries::size_type i = entries.size() - 1; |
|||
const typename Entries::value_type::context_type &ctx = entries[i].context; |
|||
|
|||
detail::info_map infoin, infoout; |
|||
|
|||
BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close); |
|||
detail::stream_info si1(close_stream(), false); |
|||
si1.type_ = detail::stream_info::use_handle; |
|||
si1.handle_ = pipes[i - 1].rend().release(); |
|||
infoin.insert(detail::info_map::value_type(STDIN_FILENO, si1)); |
|||
|
|||
if (ctx.stdout_behavior.get_type() != stream_behavior::close) |
|||
{ |
|||
detail::stream_info si = detail::stream_info(ctx.stdout_behavior, true); |
|||
infoout.insert(detail::info_map::value_type(STDOUT_FILENO, si)); |
|||
} |
|||
|
|||
if (ctx.stderr_behavior.get_type() != stream_behavior::close) |
|||
{ |
|||
detail::stream_info si = detail::stream_info(ctx.stderr_behavior, true); |
|||
infoout.insert(detail::info_map::value_type(STDERR_FILENO, si)); |
|||
} |
|||
|
|||
detail::posix_setup s; |
|||
s.work_directory = ctx.work_directory; |
|||
|
|||
pid_t pid = detail::posix_start(entries[i].executable, entries[i].arguments, ctx.environment, infoin, infoout, s); |
|||
|
|||
detail::file_handle fhstdout, fhstderr; |
|||
|
|||
if (ctx.stdout_behavior.get_type() == stream_behavior::capture) |
|||
{ |
|||
fhstdout = detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true); |
|||
BOOST_ASSERT(fhstdout.valid()); |
|||
} |
|||
|
|||
if (ctx.stderr_behavior.get_type() == stream_behavior::capture) |
|||
{ |
|||
fhstderr = detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true); |
|||
BOOST_ASSERT(fhstderr.valid()); |
|||
} |
|||
|
|||
cs.push_back(child(pid, fhinvalid, fhstdout, fhstderr)); |
|||
} |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
STARTUPINFOA si; |
|||
detail::win32_setup s; |
|||
s.startupinfo = &si; |
|||
|
|||
{ |
|||
typename Entries::size_type i = 0; |
|||
const typename Entries::value_type::context_type &ctx = entries[i].context; |
|||
|
|||
detail::stream_info sii = detail::stream_info(ctx.stdin_behavior, false); |
|||
detail::file_handle fhstdin; |
|||
if (sii.type_ == detail::stream_info::use_pipe) |
|||
fhstdin = sii.pipe_->wend(); |
|||
|
|||
BOOST_ASSERT(ctx.stdout_behavior.get_type() == stream_behavior::close); |
|||
detail::stream_info sio(close_stream(), true); |
|||
sio.type_ = detail::stream_info::use_handle; |
|||
sio.handle_ = pipes[i].wend().release(); |
|||
|
|||
detail::stream_info sie(ctx.stderr_behavior, true); |
|||
|
|||
s.work_directory = ctx.work_directory; |
|||
|
|||
::ZeroMemory(&si, sizeof(si)); |
|||
si.cb = sizeof(si); |
|||
PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s); |
|||
|
|||
if (!::CloseHandle(pi.hThread)) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed")); |
|||
|
|||
cs.push_back(child(pi.dwProcessId, fhstdin, fhinvalid, fhinvalid, detail::file_handle(pi.hProcess))); |
|||
} |
|||
|
|||
for (typename Entries::size_type i = 1; i < entries.size() - 1; ++i) |
|||
{ |
|||
const typename Entries::value_type::context_type &ctx = entries[i].context; |
|||
|
|||
BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close); |
|||
detail::stream_info sii(close_stream(), false); |
|||
sii.type_ = detail::stream_info::use_handle; |
|||
sii.handle_ = pipes[i - 1].rend().release(); |
|||
|
|||
detail::stream_info sio(close_stream(), true); |
|||
sio.type_ = detail::stream_info::use_handle; |
|||
sio.handle_ = pipes[i].wend().release(); |
|||
|
|||
detail::stream_info sie(ctx.stderr_behavior, true); |
|||
|
|||
s.work_directory = ctx.work_directory; |
|||
|
|||
::ZeroMemory(&si, sizeof(si)); |
|||
si.cb = sizeof(si); |
|||
PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s); |
|||
|
|||
if (!::CloseHandle(pi.hThread)) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed")); |
|||
|
|||
cs.push_back(child(pi.dwProcessId, fhinvalid, fhinvalid, fhinvalid, detail::file_handle(pi.hProcess))); |
|||
} |
|||
|
|||
{ |
|||
typename Entries::size_type i = entries.size() - 1; |
|||
const typename Entries::value_type::context_type &ctx = entries[i].context; |
|||
|
|||
BOOST_ASSERT(ctx.stdin_behavior.get_type() == stream_behavior::close); |
|||
detail::stream_info sii(close_stream(), false); |
|||
sii.type_ = detail::stream_info::use_handle; |
|||
sii.handle_ = pipes[i - 1].rend().release(); |
|||
|
|||
detail::file_handle fhstdout, fhstderr; |
|||
|
|||
detail::stream_info sio(ctx.stdout_behavior, true); |
|||
if (sio.type_ == detail::stream_info::use_pipe) |
|||
fhstdout = sio.pipe_->rend(); |
|||
detail::stream_info sie(ctx.stderr_behavior, true); |
|||
if (sie.type_ == detail::stream_info::use_pipe) |
|||
fhstderr = sie.pipe_->rend(); |
|||
|
|||
s.work_directory = ctx.work_directory; |
|||
|
|||
::ZeroMemory(&si, sizeof(si)); |
|||
si.cb = sizeof(si); |
|||
PROCESS_INFORMATION pi = detail::win32_start(entries[i].executable, entries[i].arguments, ctx.environment, sii, sio, sie, s); |
|||
|
|||
if (!::CloseHandle(pi.hThread)) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::launch_pipeline: CloseHandle failed")); |
|||
|
|||
cs.push_back(child(pi.dwProcessId, fhinvalid, fhstdout, fhstderr, detail::file_handle(pi.hProcess))); |
|||
} |
|||
#endif |
|||
|
|||
return cs; |
|||
} |
|||
|
|||
/**
|
|||
* Waits for a collection of children to terminate. |
|||
* |
|||
* Given a collection of Child objects (such as std::vector<child> or |
|||
* the convenience children type), waits for the termination of all of |
|||
* them. |
|||
* |
|||
* \remark Blocking remarks: This call blocks if any of the children |
|||
* processes in the collection has not finalized execution and |
|||
* waits until it terminates. |
|||
* |
|||
* \return The exit status of the first process that returns an error |
|||
* code or, if all of them executed correctly, the exit status |
|||
* of the last process in the collection. |
|||
*/ |
|||
template <class Children> |
|||
inline status wait_children(Children &cs) |
|||
{ |
|||
BOOST_ASSERT(cs.size() >= 2); |
|||
|
|||
typename Children::iterator it = cs.begin(); |
|||
while (it != cs.end()) |
|||
{ |
|||
const status s = it->wait(); |
|||
++it; |
|||
if (it == cs.end()) |
|||
return s; |
|||
else if (!s.exited() || s.exit_status() != EXIT_SUCCESS) |
|||
{ |
|||
while (it != cs.end()) |
|||
{ |
|||
it->wait(); |
|||
++it; |
|||
} |
|||
return s; |
|||
} |
|||
} |
|||
|
|||
BOOST_ASSERT(false); |
|||
return cs.begin()->wait(); |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,116 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/pistream.hpp |
|||
* |
|||
* Includes the declaration of the pistream class. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_PISTREAM_HPP |
|||
#define BOOST_PROCESS_PISTREAM_HPP |
|||
|
|||
#include <boost/process/detail/file_handle.hpp> |
|||
#include <boost/process/detail/systembuf.hpp> |
|||
#include <boost/noncopyable.hpp> |
|||
#include <istream> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Child process' output stream. |
|||
* |
|||
* The pistream class represents an output communication channel with the |
|||
* child process. The child process writes data to this stream and the |
|||
* parent process can read it through the pistream object. In other |
|||
* words, from the child's point of view, the communication channel is an |
|||
* output one, but from the parent's point of view it is an input one; |
|||
* hence the confusing pistream name. |
|||
* |
|||
* pistream objects cannot be copied because they own the file handle |
|||
* they use to communicate with the child and because they buffer data |
|||
* that flows through the communication channel. |
|||
* |
|||
* A pistream object behaves as a std::istream stream in all senses. |
|||
* The class is only provided because it must provide a method to let |
|||
* the caller explicitly close the communication channel. |
|||
* |
|||
* \remark Blocking remarks: Functions that read data from this |
|||
* stream can block if the associated file handle blocks during |
|||
* the read. As this class is used to communicate with child |
|||
* processes through anonymous pipes, the most typical blocking |
|||
* condition happens when the child has no more data to send to |
|||
* the pipe's system buffer. When this happens, the buffer |
|||
* eventually empties and the system blocks until the writer |
|||
* generates some data. |
|||
*/ |
|||
class pistream : public std::istream, public boost::noncopyable |
|||
{ |
|||
public: |
|||
/**
|
|||
* Creates a new process' output stream. |
|||
* |
|||
* Given a file handle, this constructor creates a new pistream |
|||
* object that owns the given file handle \a fh. Ownership of |
|||
* \a fh is transferred to the created pistream object. |
|||
* |
|||
* \pre \a fh is valid. |
|||
* \post \a fh is invalid. |
|||
* \post The new pistream object owns \a fh. |
|||
*/ |
|||
explicit pistream(detail::file_handle &fh) |
|||
: std::istream(0), |
|||
handle_(fh), |
|||
systembuf_(handle_.get()) |
|||
{ |
|||
rdbuf(&systembuf_); |
|||
} |
|||
|
|||
/**
|
|||
* Returns the file handle managed by this stream. |
|||
* |
|||
* The file handle must not be copied. Copying invalidates |
|||
* the source file handle making the pistream unusable. |
|||
*/ |
|||
detail::file_handle &handle() |
|||
{ |
|||
return handle_; |
|||
} |
|||
|
|||
/**
|
|||
* Closes the file handle managed by this stream. |
|||
* |
|||
* Explicitly closes the file handle managed by this stream. This |
|||
* function can be used by the user to tell the child process it's |
|||
* not willing to receive more data. |
|||
*/ |
|||
void close() |
|||
{ |
|||
handle_.close(); |
|||
} |
|||
|
|||
private: |
|||
/**
|
|||
* The file handle managed by this stream. |
|||
*/ |
|||
detail::file_handle handle_; |
|||
|
|||
/**
|
|||
* The systembuf object used to manage this stream's data. |
|||
*/ |
|||
detail::systembuf systembuf_; |
|||
}; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,178 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/posix_child.hpp |
|||
* |
|||
* Includes the declaration of the posix_child class. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_POSIX_CHILD_HPP |
|||
#define BOOST_PROCESS_POSIX_CHILD_HPP |
|||
|
|||
#include <boost/process/child.hpp> |
|||
#include <boost/process/pistream.hpp> |
|||
#include <boost/process/postream.hpp> |
|||
#include <boost/process/detail/pipe.hpp> |
|||
#include <boost/process/detail/posix_ops.hpp> |
|||
#include <boost/process/detail/stream_info.hpp> |
|||
#include <boost/shared_ptr.hpp> |
|||
#include <boost/assert.hpp> |
|||
#include <map> |
|||
#include <unistd.h> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* POSIX implementation of the Child concept. |
|||
* |
|||
* The posix_child class implements the Child concept in a POSIX |
|||
* operating system. |
|||
* |
|||
* A POSIX child differs from a regular child (represented by a |
|||
* child object) in that it supports more than three communication |
|||
* channels with its parent. These channels are identified by regular |
|||
* file descriptors (integers). |
|||
* |
|||
* This class is built on top of the generic child so as to allow its |
|||
* trivial adoption. When a program is changed to use the POSIX-specific |
|||
* context (posix_context), it will most certainly need to migrate its |
|||
* use of the child class to posix_child. Doing so is only a matter of |
|||
* redefining the appropriate object and later using the required extra |
|||
* features: there should be no need to modify the existing code (e.g. |
|||
* method calls) in any other way. |
|||
*/ |
|||
class posix_child : public child |
|||
{ |
|||
public: |
|||
/**
|
|||
* Gets a reference to the child's input stream \a desc. |
|||
* |
|||
* Returns a reference to a postream object that represents one of |
|||
* the multiple input communication channels with the child process. |
|||
* The channel is identified by \a desc as seen from the child's |
|||
* point of view. The parent can use the returned stream to send |
|||
* data to the child. |
|||
* |
|||
* Giving this function the STDIN_FILENO constant (defined in |
|||
* unistd.h) is a synonym for the get_stdin() call inherited from |
|||
* child. |
|||
*/ |
|||
postream &get_input(int desc) const |
|||
{ |
|||
if (desc == STDIN_FILENO) |
|||
return posix_child::get_stdin(); |
|||
else |
|||
{ |
|||
input_map_t::const_iterator it = input_map_.find(desc); |
|||
BOOST_ASSERT(it != input_map_.end()); |
|||
return *it->second; |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* Gets a reference to the child's output stream \a desc. |
|||
* |
|||
* Returns a reference to a pistream object that represents one of |
|||
* the multiple output communication channels with the child process. |
|||
* The channel is identified by \a desc as seen from the child's |
|||
* point of view. The parent can use the returned stream to retrieve |
|||
* data from the child. |
|||
* |
|||
* Giving this function the STDOUT_FILENO or STDERR_FILENO constants |
|||
* (both defined in unistd.h) are synonyms for the get_stdout() and |
|||
* get_stderr() calls inherited from child, respectively. |
|||
*/ |
|||
pistream &get_output(int desc) const |
|||
{ |
|||
if (desc == STDOUT_FILENO) |
|||
return posix_child::get_stdout(); |
|||
else if (desc == STDERR_FILENO) |
|||
return posix_child::get_stderr(); |
|||
else |
|||
{ |
|||
output_map_t::const_iterator it = output_map_.find(desc); |
|||
BOOST_ASSERT(it != output_map_.end()); |
|||
return *it->second; |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* Constructs a new POSIX child object representing a just |
|||
* spawned child process. |
|||
* |
|||
* Creates a new child object that represents the just spawned process |
|||
* \a id. |
|||
* |
|||
* The \a infoin and \a infoout maps contain the pipes used to handle |
|||
* the redirections of the child process; at the moment, no other |
|||
* stream_info types are supported. If the launcher was asked to |
|||
* redirect any of the three standard flows, their pipes must be |
|||
* present in these maps. |
|||
*/ |
|||
posix_child(id_type id, detail::info_map &infoin, detail::info_map &infoout) |
|||
: child(id, |
|||
detail::posix_info_locate_pipe(infoin, STDIN_FILENO, false), |
|||
detail::posix_info_locate_pipe(infoout, STDOUT_FILENO, true), |
|||
detail::posix_info_locate_pipe(infoout, STDERR_FILENO, true)) |
|||
{ |
|||
for (detail::info_map::iterator it = infoin.begin(); it != infoin.end(); ++it) |
|||
{ |
|||
detail::stream_info &si = it->second; |
|||
if (si.type_ == detail::stream_info::use_pipe) |
|||
{ |
|||
BOOST_ASSERT(si.pipe_->wend().valid()); |
|||
boost::shared_ptr<postream> st(new postream(si.pipe_->wend())); |
|||
input_map_.insert(input_map_t::value_type(it->first, st)); |
|||
} |
|||
} |
|||
|
|||
for (detail::info_map::iterator it = infoout.begin(); it != infoout.end(); ++it) |
|||
{ |
|||
detail::stream_info &si = it->second; |
|||
if (si.type_ == detail::stream_info::use_pipe) |
|||
{ |
|||
BOOST_ASSERT(si.pipe_->rend().valid()); |
|||
boost::shared_ptr<pistream> st(new pistream(si.pipe_->rend())); |
|||
output_map_.insert(output_map_t::value_type(it->first, st)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private: |
|||
/**
|
|||
* Maps child's file descriptors to postream objects. |
|||
*/ |
|||
typedef std::map<int, boost::shared_ptr<postream> > input_map_t; |
|||
|
|||
/**
|
|||
* Contains all relationships between child's input file |
|||
* descriptors and their corresponding postream objects. |
|||
*/ |
|||
input_map_t input_map_; |
|||
|
|||
/**
|
|||
* Maps child's file descriptors to pistream objects. |
|||
*/ |
|||
typedef std::map<int, boost::shared_ptr<pistream> > output_map_t; |
|||
|
|||
/**
|
|||
* Contains all relationships between child's output file |
|||
* descriptors and their corresponding pistream objects. |
|||
*/ |
|||
output_map_t output_map_; |
|||
}; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,118 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/posix_context.hpp |
|||
* |
|||
* Includes the declaration of the posix_context class. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_POSIX_CONTEXT_HPP |
|||
#define BOOST_PROCESS_POSIX_CONTEXT_HPP |
|||
|
|||
#include <boost/process/context.hpp> |
|||
#include <boost/process/stream_behavior.hpp> |
|||
#include <map> |
|||
#include <string> |
|||
#include <unistd.h> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Holds a mapping between native file descriptors and their corresponding |
|||
* pipes to set up communication between the parent and the %child process. |
|||
*/ |
|||
typedef std::map<int, stream_behavior> behavior_map; |
|||
|
|||
template <class Path> |
|||
class posix_basic_context : public basic_work_directory_context<Path>, public environment_context |
|||
{ |
|||
public: |
|||
/**
|
|||
* Constructs a new POSIX-specific context. |
|||
* |
|||
* Constructs a new context. It is configured as follows: |
|||
* * All communcation channels with the child process are closed. |
|||
* * There are no channel mergings. |
|||
* * The initial work directory of the child processes is set to the |
|||
* current working directory. |
|||
* * The environment variables table is empty. |
|||
* * The credentials are the same as those of the current process. |
|||
*/ |
|||
posix_basic_context() |
|||
: uid(::getuid()), |
|||
euid(::geteuid()), |
|||
gid(::getgid()), |
|||
egid(::getegid()) |
|||
{ |
|||
} |
|||
|
|||
/**
|
|||
* List of input streams that will be redirected. |
|||
*/ |
|||
behavior_map input_behavior; |
|||
|
|||
/**
|
|||
* List of output streams that will be redirected. |
|||
*/ |
|||
behavior_map output_behavior; |
|||
|
|||
/**
|
|||
* The user credentials. |
|||
* |
|||
* UID that specifies the user credentials to use to run the %child |
|||
* process. Defaults to the current UID. |
|||
*/ |
|||
uid_t uid; |
|||
|
|||
/**
|
|||
* The effective user credentials. |
|||
* |
|||
* EUID that specifies the effective user credentials to use to run |
|||
* the %child process. Defaults to the current EUID. |
|||
*/ |
|||
uid_t euid; |
|||
|
|||
/**
|
|||
* The group credentials. |
|||
* |
|||
* GID that specifies the group credentials to use to run the %child |
|||
* process. Defaults to the current GID. |
|||
*/ |
|||
gid_t gid; |
|||
|
|||
/**
|
|||
* The effective group credentials. |
|||
* |
|||
* EGID that specifies the effective group credentials to use to run |
|||
* the %child process. Defaults to the current EGID. |
|||
*/ |
|||
gid_t egid; |
|||
|
|||
/**
|
|||
* The chroot directory, if any. |
|||
* |
|||
* Specifies the directory in which the %child process is chrooted |
|||
* before execution. Empty if this feature is not desired. |
|||
*/ |
|||
Path chroot; |
|||
}; |
|||
|
|||
/**
|
|||
* Default instantiation of posix_basic_context. |
|||
*/ |
|||
typedef posix_basic_context<std::string> posix_context; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,81 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/posix_operations.hpp |
|||
* |
|||
* Provides miscellaneous free functions specific to POSIX operating |
|||
* systems. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_POSIX_OPERATIONS_HPP |
|||
#define BOOST_PROCESS_POSIX_OPERATIONS_HPP |
|||
|
|||
#include <boost/process/posix_child.hpp> |
|||
#include <boost/process/posix_context.hpp> |
|||
#include <boost/process/stream_behavior.hpp> |
|||
#include <boost/process/detail/stream_info.hpp> |
|||
#include <boost/process/detail/posix_ops.hpp> |
|||
#include <sys/types.h> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Starts a new child process. |
|||
* |
|||
* Given an executable and the set of arguments passed to it, starts |
|||
* a new process with all the parameters configured in the context. |
|||
* The context can be reused afterwards to launch other different |
|||
* processes. |
|||
* |
|||
* \return A handle to the new child process. |
|||
*/ |
|||
template <class Executable, class Arguments, class Posix_Context> |
|||
inline posix_child posix_launch(const Executable &exe, const Arguments &args, const Posix_Context &ctx) |
|||
{ |
|||
detail::info_map input_info; |
|||
for (behavior_map::const_iterator it = ctx.input_behavior.begin(); it != ctx.input_behavior.end(); ++it) |
|||
{ |
|||
if (it->second.get_type() != stream_behavior::close) |
|||
{ |
|||
detail::stream_info si = detail::stream_info(it->second, false); |
|||
input_info.insert(detail::info_map::value_type(it->first, si)); |
|||
} |
|||
} |
|||
|
|||
detail::info_map output_info; |
|||
for (behavior_map::const_iterator it = ctx.output_behavior.begin(); it != ctx.output_behavior.end(); ++it) |
|||
{ |
|||
if (it->second.get_type() != stream_behavior::close) |
|||
{ |
|||
detail::stream_info si = detail::stream_info(it->second, true); |
|||
output_info.insert(detail::info_map::value_type(it->first, si)); |
|||
} |
|||
} |
|||
|
|||
detail::posix_setup s; |
|||
s.work_directory = ctx.work_directory; |
|||
s.uid = ctx.uid; |
|||
s.euid = ctx.euid; |
|||
s.gid = ctx.gid; |
|||
s.egid = ctx.egid; |
|||
s.chroot = ctx.chroot; |
|||
|
|||
pid_t pid = detail::posix_start(exe, args, ctx.environment, input_info, output_info, s); |
|||
|
|||
return posix_child(pid, input_info, output_info); |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,128 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/posix_status.hpp |
|||
* |
|||
* Includes the declaration of the posix_status class. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_POSIX_STATUS_HPP |
|||
#define BOOST_PROCESS_POSIX_STATUS_HPP |
|||
|
|||
#include <boost/process/config.hpp> |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
# include <sys/wait.h> |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
#else |
|||
# error "Unsupported platform." |
|||
#endif |
|||
|
|||
#include <boost/process/status.hpp> |
|||
#include <boost/assert.hpp> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Status returned by a finalized %child process on a POSIX system. |
|||
* |
|||
* This class represents the %status returned by a child process after it |
|||
* has terminated. It contains some methods not available in the status |
|||
* class that provide information only available in POSIX systems. |
|||
*/ |
|||
class posix_status : public status |
|||
{ |
|||
public: |
|||
/**
|
|||
* Creates a posix_status object from an existing status object. |
|||
* |
|||
* Creates a new status object representing the exit status of a |
|||
* child process. The construction is done based on an existing |
|||
* status object which already contains all the available |
|||
* information: this class only provides controlled access to it. |
|||
*/ |
|||
posix_status(const status &s) |
|||
: status(s) |
|||
{ |
|||
} |
|||
|
|||
/**
|
|||
* Returns whether the process exited due to an external |
|||
* signal. |
|||
*/ |
|||
bool signaled() const |
|||
{ |
|||
return WIFSIGNALED(flags_); |
|||
} |
|||
|
|||
/**
|
|||
* If signaled, returns the terminating signal code. |
|||
* |
|||
* If the process was signaled, returns the terminating signal code. |
|||
* |
|||
* \pre signaled() is true. |
|||
*/ |
|||
int term_signal() const |
|||
{ |
|||
BOOST_ASSERT(signaled()); |
|||
|
|||
return WTERMSIG(flags_); |
|||
} |
|||
|
|||
/**
|
|||
* If signaled, returns whether the process dumped core. |
|||
* |
|||
* If the process was signaled, returns whether the process |
|||
* produced a core dump. |
|||
* |
|||
* \pre signaled() is true. |
|||
*/ |
|||
bool dumped_core() const |
|||
{ |
|||
BOOST_ASSERT(signaled()); |
|||
|
|||
#ifdef WCOREDUMP |
|||
return WCOREDUMP(flags_); |
|||
#else |
|||
return false; |
|||
#endif |
|||
} |
|||
|
|||
/**
|
|||
* Returns whether the process was stopped by an external |
|||
* signal. |
|||
*/ |
|||
bool stopped() const |
|||
{ |
|||
return WIFSTOPPED(flags_); |
|||
} |
|||
|
|||
/**
|
|||
* If stopped, returns the stop signal code. |
|||
* |
|||
* If the process was stopped, returns the stop signal code. |
|||
* |
|||
* \pre stopped() is true. |
|||
*/ |
|||
int stop_signal() const |
|||
{ |
|||
BOOST_ASSERT(stopped()); |
|||
|
|||
return WSTOPSIG(flags_); |
|||
} |
|||
}; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,117 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/postream.hpp |
|||
* |
|||
* Includes the declaration of the postream class. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_POSTREAM_HPP |
|||
#define BOOST_PROCESS_POSTREAM_HPP |
|||
|
|||
#include <boost/process/detail/file_handle.hpp> |
|||
#include <boost/process/detail/systembuf.hpp> |
|||
#include <boost/noncopyable.hpp> |
|||
#include <ostream> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Child process' input stream. |
|||
* |
|||
* The postream class represents an input communication channel with the |
|||
* child process. The child process reads data from this stream and the |
|||
* parent process can write to it through the postream object. In other |
|||
* words, from the child's point of view, the communication channel is an |
|||
* input one, but from the parent's point of view it is an output one; |
|||
* hence the confusing postream name. |
|||
* |
|||
* postream objects cannot be copied because they own the file handle |
|||
* they use to communicate with the child and because they buffer data |
|||
* that flows through the communication channel. |
|||
* |
|||
* A postream object behaves as a std::ostream stream in all senses. |
|||
* The class is only provided because it must provide a method to let |
|||
* the caller explicitly close the communication channel. |
|||
* |
|||
* \remark Blocking remarks: Functions that write data to this |
|||
* stream can block if the associated file handle blocks during |
|||
* the write. As this class is used to communicate with child |
|||
* processes through anonymous pipes, the most typical blocking |
|||
* condition happens when the child is not processing the data |
|||
* in the pipe's system buffer. When this happens, the buffer |
|||
* eventually fills up and the system blocks until the reader |
|||
* consumes some data, leaving some new room. |
|||
*/ |
|||
class postream : public std::ostream, public boost::noncopyable |
|||
{ |
|||
public: |
|||
/**
|
|||
* Creates a new process' input stream. |
|||
* |
|||
* Given a file handle, this constructor creates a new postream |
|||
* object that owns the given file handle \a fh. Ownership of |
|||
* \a fh is transferred to the created postream object. |
|||
* |
|||
* \pre \a fh is valid. |
|||
* \post \a fh is invalid. |
|||
* \post The new postream object owns \a fh. |
|||
*/ |
|||
explicit postream(detail::file_handle &fh) |
|||
: std::ostream(0), |
|||
handle_(fh), |
|||
systembuf_(handle_.get()) |
|||
{ |
|||
rdbuf(&systembuf_); |
|||
} |
|||
|
|||
/**
|
|||
* Returns the file handle managed by this stream. |
|||
* |
|||
* The file handle must not be copied. Copying invalidates |
|||
* the source file handle making the postream unusable. |
|||
*/ |
|||
detail::file_handle &handle() |
|||
{ |
|||
return handle_; |
|||
} |
|||
|
|||
/**
|
|||
* Closes the file handle managed by this stream. |
|||
* |
|||
* Explicitly closes the file handle managed by this stream. This |
|||
* function can be used by the user to tell the child process there |
|||
* is no more data to send. |
|||
*/ |
|||
void close() |
|||
{ |
|||
systembuf_.sync(); |
|||
handle_.close(); |
|||
} |
|||
|
|||
private: |
|||
/**
|
|||
* The file handle managed by this stream. |
|||
*/ |
|||
detail::file_handle handle_; |
|||
|
|||
/**
|
|||
* The systembuf object used to manage this stream's data. |
|||
*/ |
|||
detail::systembuf systembuf_; |
|||
}; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,130 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/process.hpp |
|||
* |
|||
* Includes the declaration of the process class. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_PROCESS_HPP |
|||
#define BOOST_PROCESS_PROCESS_HPP |
|||
|
|||
#include <boost/process/config.hpp> |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
# include <cerrno> |
|||
# include <signal.h> |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
# include <cstdlib> |
|||
# include <windows.h> |
|||
#else |
|||
# error "Unsupported platform." |
|||
#endif |
|||
|
|||
#include <boost/system/system_error.hpp> |
|||
#include <boost/throw_exception.hpp> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Generic implementation of the Process concept. |
|||
* |
|||
* The process class implements the Process concept in an operating system |
|||
* agnostic way. |
|||
*/ |
|||
class process |
|||
{ |
|||
public: |
|||
#if defined(BOOST_PROCESS_DOXYGEN) |
|||
/**
|
|||
* Opaque name for the native process' identifier type. |
|||
* |
|||
* Each operating system identifies processes using a specific type. |
|||
* The \a id_type type is used to transparently refer to a process |
|||
* regardless of the operating system in which this class is used. |
|||
* |
|||
* This type is guaranteed to be an integral type on all supported |
|||
* platforms. |
|||
*/ |
|||
typedef NativeProcessId id_type; |
|||
#elif defined(BOOST_POSIX_API) |
|||
typedef pid_t id_type; |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
typedef DWORD id_type; |
|||
#endif |
|||
|
|||
/**
|
|||
* Constructs a new process object. |
|||
* |
|||
* Creates a new process object that represents a running process |
|||
* within the system. |
|||
*/ |
|||
process(id_type id) |
|||
: id_(id) |
|||
{ |
|||
} |
|||
|
|||
/**
|
|||
* Returns the process' identifier. |
|||
*/ |
|||
id_type get_id() const |
|||
{ |
|||
return id_; |
|||
} |
|||
|
|||
/**
|
|||
* Terminates the process execution. |
|||
* |
|||
* Forces the termination of the process execution. Some platforms |
|||
* allow processes to ignore some external termination notifications |
|||
* or to capture them for a proper exit cleanup. You can set the |
|||
* \a force flag to true in them to force their termination regardless |
|||
* of any exit handler. |
|||
* |
|||
* After this call, accessing this object can be dangerous because the |
|||
* process identifier may have been reused by a different process. It |
|||
* might still be valid, though, if the process has refused to die. |
|||
* |
|||
* \throw boost::system::system_error If the system call used to |
|||
* terminate the process fails. |
|||
*/ |
|||
void terminate(bool force = false) const |
|||
{ |
|||
#if defined(BOOST_POSIX_API) |
|||
if (::kill(id_, force ? SIGKILL : SIGTERM) == -1) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(errno, boost::system::get_system_category()), "boost::process::process::terminate: kill(2) failed")); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
HANDLE h = ::OpenProcess(PROCESS_TERMINATE, FALSE, id_); |
|||
if (h == NULL) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: OpenProcess failed")); |
|||
if (!::TerminateProcess(h, EXIT_FAILURE)) |
|||
{ |
|||
::CloseHandle(h); |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: TerminateProcess failed")); |
|||
} |
|||
if (!::CloseHandle(h)) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::process::terminate: CloseHandle failed")); |
|||
#endif |
|||
} |
|||
|
|||
private: |
|||
/**
|
|||
* The process' identifier. |
|||
*/ |
|||
id_type id_; |
|||
}; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,134 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/self.hpp |
|||
* |
|||
* Includes the declaration of the self class. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_SELF_HPP |
|||
#define BOOST_PROCESS_SELF_HPP |
|||
|
|||
#include <boost/process/config.hpp> |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
# include <unistd.h> |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
# include <windows.h> |
|||
#else |
|||
# error "Unsupported platform." |
|||
#endif |
|||
|
|||
#include <boost/process/process.hpp> |
|||
#include <boost/process/environment.hpp> |
|||
#include <boost/system/system_error.hpp> |
|||
#include <boost/throw_exception.hpp> |
|||
#include <boost/noncopyable.hpp> |
|||
#include <string> |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
extern "C" |
|||
{ |
|||
extern char **environ; |
|||
} |
|||
#endif |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Generic implementation of the Process concept. |
|||
* |
|||
* The self singleton provides access to the current process. |
|||
*/ |
|||
class self : public process, boost::noncopyable |
|||
{ |
|||
public: |
|||
/**
|
|||
* Returns the self instance representing the caller's process. |
|||
*/ |
|||
static self &get_instance() |
|||
{ |
|||
static self *instance = 0; |
|||
if (!instance) |
|||
instance = new self; |
|||
return *instance; |
|||
} |
|||
|
|||
/**
|
|||
* Returns the current environment. |
|||
* |
|||
* Returns the current process' environment variables. Modifying the |
|||
* returned object has no effect on the current environment. |
|||
*/ |
|||
static environment get_environment() |
|||
{ |
|||
environment e; |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
char **env = ::environ; |
|||
while (*env) |
|||
{ |
|||
std::string s = *env; |
|||
std::string::size_type pos = s.find('='); |
|||
e.insert(boost::process::environment::value_type(s.substr(0, pos), s.substr(pos + 1))); |
|||
++env; |
|||
} |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
#ifdef GetEnvironmentStrings |
|||
#undef GetEnvironmentStrings |
|||
#endif |
|||
char *environ = ::GetEnvironmentStrings(); |
|||
if (!environ) |
|||
boost::throw_exception(boost::system::system_error(boost::system::error_code(::GetLastError(), boost::system::get_system_category()), "boost::process::self::get_environment: GetEnvironmentStrings failed")); |
|||
try |
|||
{ |
|||
char *env = environ; |
|||
while (*env) |
|||
{ |
|||
std::string s = env; |
|||
std::string::size_type pos = s.find('='); |
|||
e.insert(boost::process::environment::value_type(s.substr(0, pos), s.substr(pos + 1))); |
|||
env += s.size() + 1; |
|||
} |
|||
} |
|||
catch (...) |
|||
{ |
|||
::FreeEnvironmentStringsA(environ); |
|||
throw; |
|||
} |
|||
::FreeEnvironmentStringsA(environ); |
|||
#endif |
|||
|
|||
return e; |
|||
} |
|||
|
|||
private: |
|||
/**
|
|||
* Constructs a new self object. |
|||
* |
|||
* Creates a new self object that represents the current process. |
|||
*/ |
|||
self() : |
|||
#if defined(BOOST_POSIX_API) |
|||
process(::getpid()) |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
process(::GetCurrentProcessId()) |
|||
#endif |
|||
{ |
|||
} |
|||
}; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,105 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/status.hpp |
|||
* |
|||
* Includes the declaration of the status class. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_STATUS_HPP |
|||
#define BOOST_PROCESS_STATUS_HPP |
|||
|
|||
#include <boost/process/config.hpp> |
|||
|
|||
#if defined(BOOST_POSIX_API) |
|||
# include <sys/wait.h> |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
#else |
|||
# error "Unsupported platform." |
|||
#endif |
|||
|
|||
#include <boost/assert.hpp> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
class child; |
|||
|
|||
/**
|
|||
* Status returned by a finalized %child process. |
|||
* |
|||
* This class represents the %status returned by a child process after it |
|||
* has terminated. It only provides that information available under all |
|||
* supported platforms. |
|||
* |
|||
* \see posix_status |
|||
*/ |
|||
class status |
|||
{ |
|||
friend class child; |
|||
|
|||
public: |
|||
/**
|
|||
* Returns whether the process exited gracefully or not. |
|||
*/ |
|||
bool exited() const |
|||
{ |
|||
#if defined(BOOST_POSIX_API) |
|||
return WIFEXITED(flags_); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
return true; |
|||
#endif |
|||
} |
|||
|
|||
/**
|
|||
* If exited, returns the exit code. |
|||
* |
|||
* If the process exited, returns the exit code it returned. |
|||
* |
|||
* \pre exited() is true. |
|||
*/ |
|||
int exit_status() const |
|||
{ |
|||
BOOST_ASSERT(exited()); |
|||
#if defined(BOOST_POSIX_API) |
|||
return WEXITSTATUS(flags_); |
|||
#elif defined(BOOST_WINDOWS_API) |
|||
return flags_; |
|||
#endif |
|||
} |
|||
|
|||
protected: |
|||
/**
|
|||
* Creates a status object based on exit information. |
|||
* |
|||
* Creates a new status object representing the exit status of a |
|||
* child process. |
|||
* |
|||
* \param flags In a POSIX system this parameter contains the |
|||
* flags returned by the ::waitpid() call. In a |
|||
* Windows system it contains the exit code only. |
|||
*/ |
|||
status(int flags) |
|||
: flags_(flags) |
|||
{ |
|||
} |
|||
|
|||
/**
|
|||
* OS-specific codification of exit status. |
|||
*/ |
|||
int flags_; |
|||
}; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,234 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/stream_behavior.hpp |
|||
* |
|||
* Includes the declaration of the stream_behavior class and associated |
|||
* free functions. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_STREAM_BEHAVIOR_HPP |
|||
#define BOOST_PROCESS_STREAM_BEHAVIOR_HPP |
|||
|
|||
#include <boost/process/config.hpp> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
namespace detail { |
|||
struct stream_info; |
|||
} |
|||
|
|||
/**
|
|||
* Describes the possible states for a communication stream. |
|||
*/ |
|||
class stream_behavior |
|||
{ |
|||
public: |
|||
friend struct detail::stream_info; |
|||
friend stream_behavior capture_stream(); |
|||
friend stream_behavior close_stream(); |
|||
friend stream_behavior inherit_stream(); |
|||
friend stream_behavior redirect_stream_to_stdout(); |
|||
friend stream_behavior silence_stream(); |
|||
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) |
|||
friend stream_behavior posix_redirect_stream(int to); |
|||
#endif |
|||
|
|||
/**
|
|||
* Describes the possible states for a communication stream. |
|||
*/ |
|||
enum type |
|||
{ |
|||
/**
|
|||
* The child's stream is connected to the parent by using an |
|||
* anonymous pipe so that they can send and receive data to/from |
|||
* each other. |
|||
*/ |
|||
capture, |
|||
|
|||
/**
|
|||
* The child's stream is closed upon startup so that it will not |
|||
* have any access to it. |
|||
*/ |
|||
close, |
|||
|
|||
/**
|
|||
* The child's stream is connected to the same stream used by the |
|||
* parent. In other words, the corresponding parent's stream is |
|||
* inherited. |
|||
*/ |
|||
inherit, |
|||
|
|||
/**
|
|||
* The child's stream is connected to child's standard output. |
|||
* This is typically used when configuring the standard error |
|||
* stream. |
|||
*/ |
|||
redirect_to_stdout, |
|||
|
|||
/**
|
|||
* The child's stream is redirected to a null device so that its |
|||
* input is always zero or its output is lost, depending on |
|||
* whether the stream is an input or an output one. It is |
|||
* important to notice that this is different from close because |
|||
* the child is still able to write data. If we closed, e.g. |
|||
* stdout, the child might not work at all! |
|||
*/ |
|||
silence, |
|||
|
|||
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) |
|||
/**
|
|||
* The child redirects the stream's output to the provided file |
|||
* descriptor. This is a generalization of the portable |
|||
* redirect_to_stdout behavior. |
|||
*/ |
|||
posix_redirect |
|||
#endif |
|||
}; |
|||
|
|||
/**
|
|||
* Constructs a new stream behavior of type close. |
|||
* |
|||
* The public constructor creates a new stream behavior that defaults |
|||
* to the close behavior. In general, you will want to use the |
|||
* available free functions to construct a stream behavior (including |
|||
* the close one). |
|||
*/ |
|||
stream_behavior() |
|||
: type_(stream_behavior::close) |
|||
{ |
|||
} |
|||
|
|||
/**
|
|||
* Returns this stream's behavior type. |
|||
*/ |
|||
type get_type() const |
|||
{ |
|||
return type_; |
|||
} |
|||
|
|||
private: |
|||
/**
|
|||
* Constructs a new stream behavior of type \a t. |
|||
* |
|||
* Constructs a new stream behavior of type \a t. It is the |
|||
* responsibility of the caller to fill in any other attributes |
|||
* required by the specified type, if any. |
|||
*/ |
|||
stream_behavior(type t) |
|||
: type_(t) |
|||
{ |
|||
} |
|||
|
|||
/**
|
|||
* This stream's behavior type. |
|||
*/ |
|||
type type_; |
|||
|
|||
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) |
|||
/**
|
|||
* File descriptor the stream is redirected to. |
|||
*/ |
|||
int desc_to_; |
|||
#endif |
|||
}; |
|||
|
|||
/**
|
|||
* Creates a new stream_behavior of type stream_behavior::capture. |
|||
* |
|||
* Creates a new stream_behavior of type stream_behavior::capture, |
|||
* meaning that the child's stream is connected to the parent by using an |
|||
* anonymous pipe so that they can send and receive data to/from each |
|||
* other. |
|||
*/ |
|||
inline stream_behavior capture_stream() |
|||
{ |
|||
return stream_behavior(stream_behavior::capture); |
|||
} |
|||
|
|||
/**
|
|||
* Creates a new stream_behavior of type stream_behavior::close. |
|||
* |
|||
* Creates a new stream_behavior of type stream_behavior::close, |
|||
* meaning that the child's stream is closed upon startup so that it |
|||
* will not have any access to it. |
|||
*/ |
|||
inline stream_behavior close_stream() |
|||
{ |
|||
return stream_behavior(stream_behavior::close); |
|||
} |
|||
|
|||
/**
|
|||
* Creates a new stream_behavior of type stream_behavior::inherit. |
|||
* |
|||
* Creates a new stream_behavior of type stream_behavior::inherit, |
|||
* meaning that the child's stream is connected to the same stream used |
|||
* by the parent. In other words, the corresponding parent's stream is |
|||
* inherited. |
|||
*/ |
|||
inline stream_behavior inherit_stream() |
|||
{ |
|||
return stream_behavior(stream_behavior::inherit); |
|||
} |
|||
|
|||
/**
|
|||
* Creates a new stream_behavior of type |
|||
* stream_behavior::redirect_to_stdout. |
|||
* |
|||
* Creates a new stream_behavior of type |
|||
* stream_behavior::redirect_to_stdout, meaning that the child's stream is |
|||
* connected to child's standard output. This is typically used when |
|||
* configuring the standard error stream. |
|||
*/ |
|||
inline stream_behavior redirect_stream_to_stdout() |
|||
{ |
|||
return stream_behavior(stream_behavior::redirect_to_stdout); |
|||
} |
|||
|
|||
/**
|
|||
* Creates a new stream_behavior of type stream_behavior::silence. |
|||
* |
|||
* Creates a new stream_behavior of type stream_behavior::silence, |
|||
* meaning that the child's stream is redirected to a null device so that |
|||
* its input is always zero or its output is lost, depending on whether |
|||
* the stream is an input or an output one. It is important to notice |
|||
* that this is different from close because the child is still able to |
|||
* write data. If we closed, e.g. stdout, the child might not work at |
|||
* all! |
|||
*/ |
|||
inline stream_behavior silence_stream() |
|||
{ |
|||
return stream_behavior(stream_behavior::silence); |
|||
} |
|||
|
|||
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) |
|||
/**
|
|||
* Creates a new stream_behavior of type stream_behavior::posix_redirect. |
|||
* |
|||
* Creates a new stream_behavior of type stream_behavior::posix_redirect, |
|||
* meaning that the child's stream is redirected to the \a to child's |
|||
* file descriptor. This is a generalization of the portable |
|||
* redirect_stream_to_stdout() behavior. |
|||
*/ |
|||
inline stream_behavior posix_redirect_stream(int to) |
|||
{ |
|||
stream_behavior sb(stream_behavior::posix_redirect); |
|||
sb.desc_to_ = to; |
|||
return sb; |
|||
} |
|||
#endif |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,128 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/win32_child.hpp |
|||
* |
|||
* Includes the declaration of the win32_child class. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_WIN32_CHILD_HPP |
|||
#define BOOST_PROCESS_WIN32_CHILD_HPP |
|||
|
|||
#include <boost/process/child.hpp> |
|||
#include <boost/process/detail/file_handle.hpp> |
|||
#include <windows.h> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Windows implementation of the Child concept. |
|||
* |
|||
* The win32_child class implements the Child concept in a Windows |
|||
* operating system. |
|||
* |
|||
* A Windows child differs from a regular %child (represented by a |
|||
* child object) in that it holds additional information about a process. |
|||
* Aside from the standard handle, it also includes a handle to the |
|||
* process' main thread, together with identifiers to both entities. |
|||
* |
|||
* This class is built on top of the generic child so as to allow its |
|||
* trivial adoption. When a program is changed to use the |
|||
* Windows-specific context (win32_context), it will most certainly need |
|||
* to migrate its use of the child class to win32_child. Doing so is only |
|||
* a matter of redefining the appropriate object and later using the |
|||
* required extra features: there should be no need to modify the existing |
|||
* code (e.g. method calls) in any other way. |
|||
*/ |
|||
class win32_child : public child |
|||
{ |
|||
public: |
|||
/**
|
|||
* Constructs a new Windows child object representing a just |
|||
* spawned %child process. |
|||
* |
|||
* Creates a new %child object that represents the process described by |
|||
* the \a pi structure. |
|||
* |
|||
* The \a fhstdin, \a fhstdout and \a fhstderr parameters hold the |
|||
* communication streams used to interact with the %child process if |
|||
* the launcher configured redirections. See the parent class' |
|||
* constructor for more details on these. |
|||
* |
|||
* \see child |
|||
*/ |
|||
win32_child(const PROCESS_INFORMATION &pi, detail::file_handle fhstdin, detail::file_handle fhstdout, detail::file_handle fhstderr) |
|||
: child(pi.dwProcessId, fhstdin, fhstdout, fhstderr, pi.hProcess), |
|||
process_information_(pi), |
|||
thread_handle_(process_information_.hThread) |
|||
{ |
|||
} |
|||
|
|||
/**
|
|||
* Returns the process handle. |
|||
* |
|||
* Returns a process-specific handle that can be used to access the |
|||
* process. This is the value of the \a hProcess field in the |
|||
* PROCESS_INFORMATION structure returned by CreateProcess(). |
|||
* |
|||
* \see get_id() |
|||
*/ |
|||
HANDLE get_handle() const |
|||
{ |
|||
return process_information_.hProcess; |
|||
} |
|||
|
|||
/**
|
|||
* Returns the primary thread's handle. |
|||
* |
|||
* Returns a handle to the primary thread of the new process. This is |
|||
* the value of the \a hThread field in the PROCESS_INFORMATION |
|||
* structure returned by CreateProcess(). |
|||
* |
|||
* \see get_primary_thread_id() |
|||
*/ |
|||
HANDLE get_primary_thread_handle() const |
|||
{ |
|||
return process_information_.hThread; |
|||
} |
|||
|
|||
/**
|
|||
* Returns the primary thread's identifier. |
|||
* |
|||
* Returns a system-wide value that identifies the process's primary |
|||
* thread. This is the value of the \a dwThreadId field in the |
|||
* PROCESS_INFORMATION structure returned by CreateProcess(). |
|||
* |
|||
* \see get_primary_thread_handle() |
|||
*/ |
|||
DWORD get_primary_thread_id() const |
|||
{ |
|||
return process_information_.dwThreadId; |
|||
} |
|||
|
|||
private: |
|||
/**
|
|||
* Windows-specific process information. |
|||
*/ |
|||
PROCESS_INFORMATION process_information_; |
|||
|
|||
/**
|
|||
* Thread handle owned by RAII object. |
|||
*/ |
|||
detail::file_handle thread_handle_; |
|||
}; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,61 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/win_32context.hpp |
|||
* |
|||
* Includes the declaration of the win32_context class. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_WIN32_CONTEXT_HPP |
|||
#define BOOST_PROCESS_WIN32_CONTEXT_HPP |
|||
|
|||
#include <boost/process/context.hpp> |
|||
#include <string> |
|||
#include <windows.h> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Generic implementation of the Context concept. |
|||
* |
|||
* The context class implements the Context concept in an operating |
|||
* system agnostic way; it allows spawning new child processes using |
|||
* a single and common interface across different systems. |
|||
*/ |
|||
template <class String> |
|||
class win32_basic_context : public basic_context<String> |
|||
{ |
|||
public: |
|||
/**
|
|||
* Initializes the Win32-specific process startup information with NULL. |
|||
*/ |
|||
win32_basic_context() |
|||
: startupinfo(NULL) |
|||
{ |
|||
} |
|||
|
|||
/**
|
|||
* Win32-specific process startup information. |
|||
*/ |
|||
STARTUPINFOA *startupinfo; |
|||
}; |
|||
|
|||
/**
|
|||
* Default instantiation of win32_basic_context. |
|||
*/ |
|||
typedef win32_basic_context<std::string> win32_context; |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,77 @@ |
|||
//
|
|||
// Boost.Process
|
|||
// ~~~~~~~~~~~~~
|
|||
//
|
|||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
|||
// Copyright (c) 2008, 2009 Boris Schaeling
|
|||
//
|
|||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||
//
|
|||
|
|||
/**
|
|||
* \file boost/process/win32_operations.hpp |
|||
* |
|||
* Provides miscellaneous free functions specific to Windows operating |
|||
* systems. |
|||
*/ |
|||
|
|||
#ifndef BOOST_PROCESS_WIN32_OPERATIONS_HPP |
|||
#define BOOST_PROCESS_WIN32_OPERATIONS_HPP |
|||
|
|||
#include <boost/process/win32_child.hpp> |
|||
#include <boost/process/detail/file_handle.hpp> |
|||
#include <boost/process/detail/stream_info.hpp> |
|||
#include <boost/process/detail/win32_ops.hpp> |
|||
#include <windows.h> |
|||
|
|||
namespace boost { |
|||
namespace process { |
|||
|
|||
/**
|
|||
* Starts a new child process. |
|||
* |
|||
* Given an executable and the set of arguments passed to it, starts |
|||
* a new process with all the parameters configured in the context. |
|||
* The context can be reused afterwards to launch other different |
|||
* processes. |
|||
* |
|||
* \return A handle to the new child process. |
|||
*/ |
|||
template <class Executable, class Arguments, class Win32_Context> |
|||
inline win32_child win32_launch(const Executable &exe, const Arguments &args, const Win32_Context &ctx) |
|||
{ |
|||
detail::file_handle fhstdin, fhstdout, fhstderr; |
|||
|
|||
detail::stream_info behin = detail::stream_info(ctx.stdin_behavior, false); |
|||
if (behin.type_ == detail::stream_info::use_pipe) |
|||
fhstdin = behin.pipe_->wend(); |
|||
detail::stream_info behout = detail::stream_info(ctx.stdout_behavior, true); |
|||
if (behout.type_ == detail::stream_info::use_pipe) |
|||
fhstdout = behout.pipe_->rend(); |
|||
detail::stream_info beherr = detail::stream_info(ctx.stderr_behavior, true); |
|||
if (beherr.type_ == detail::stream_info::use_pipe) |
|||
fhstderr = beherr.pipe_->rend(); |
|||
|
|||
detail::win32_setup s; |
|||
s.work_directory = ctx.work_directory; |
|||
|
|||
STARTUPINFOA si; |
|||
if (!ctx.startupinfo) |
|||
{ |
|||
::ZeroMemory(&si, sizeof(si)); |
|||
si.cb = sizeof(si); |
|||
s.startupinfo = &si; |
|||
} |
|||
else |
|||
s.startupinfo = ctx.startupinfo; |
|||
|
|||
PROCESS_INFORMATION pi = detail::win32_start(exe, args, ctx.environment, behin, behout, beherr, s); |
|||
|
|||
return win32_child(pi, fhstdin, fhstdout, fhstderr); |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
#endif |
@ -1,48 +0,0 @@ |
|||
cmake_policy(SET CMP0015 NEW) |
|||
|
|||
aux_source_directory(. SRC_LIST) |
|||
|
|||
include_directories(../libethereum) |
|||
link_directories(../libethereum) |
|||
|
|||
add_executable(eth ${SRC_LIST}) |
|||
|
|||
if (${TARGET_PLATFORM} STREQUAL "w64") |
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") |
|||
target_link_libraries(eth gcc) |
|||
target_link_libraries(eth gdi32) |
|||
target_link_libraries(eth ws2_32) |
|||
target_link_libraries(eth mswsock) |
|||
target_link_libraries(eth shlwapi) |
|||
target_link_libraries(eth iphlpapi) |
|||
target_link_libraries(eth cryptopp) |
|||
target_link_libraries(eth ncurses) |
|||
target_link_libraries(eth form) |
|||
target_link_libraries(eth boost_system-mt-s) |
|||
target_link_libraries(eth boost_filesystem-mt-s) |
|||
target_link_libraries(eth boost_thread_win32-mt-s) |
|||
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) |
|||
elseif (UNIX) |
|||
target_link_libraries(eth ncurses) |
|||
target_link_libraries(eth form) |
|||
else () |
|||
target_link_libraries(eth ${CRYPTOPP_LIBRARIES}) |
|||
target_link_libraries(eth boost_system) |
|||
target_link_libraries(eth boost_filesystem) |
|||
target_link_libraries(eth ncurses) |
|||
target_link_libraries(eth form) |
|||
find_package(Threads REQUIRED) |
|||
target_link_libraries(eth ${CMAKE_THREAD_LIBS_INIT}) |
|||
endif () |
|||
|
|||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") |
|||
include_directories(/usr/local/include) |
|||
endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") |
|||
|
|||
target_link_libraries(eth ethereum) |
|||
target_link_libraries(eth miniupnpc) |
|||
target_link_libraries(eth leveldb) |
|||
target_link_libraries(eth gmp) |
|||
|
|||
install( TARGETS eth DESTINATION bin ) |
|||
|
File diff suppressed because it is too large
@ -0,0 +1,379 @@ |
|||
var bigInt = (function () { |
|||
var base = 10000000, logBase = 7; |
|||
var sign = { |
|||
positive: false, |
|||
negative: true |
|||
}; |
|||
|
|||
var normalize = function (first, second) { |
|||
var a = first.value, b = second.value; |
|||
var length = a.length > b.length ? a.length : b.length; |
|||
for (var i = 0; i < length; i++) { |
|||
a[i] = a[i] || 0; |
|||
b[i] = b[i] || 0; |
|||
} |
|||
for (var i = length - 1; i >= 0; i--) { |
|||
if (a[i] === 0 && b[i] === 0) { |
|||
a.pop(); |
|||
b.pop(); |
|||
} else break; |
|||
} |
|||
if (!a.length) a = [0], b = [0]; |
|||
first.value = a; |
|||
second.value = b; |
|||
}; |
|||
|
|||
var parse = function (text, first) { |
|||
if (typeof text === "object") return text; |
|||
text += ""; |
|||
var s = sign.positive, value = []; |
|||
if (text[0] === "-") { |
|||
s = sign.negative; |
|||
text = text.slice(1); |
|||
} |
|||
var base = 10; |
|||
if (text.slice(0, 2) == "0x") { |
|||
base = 16; |
|||
text = text.slice(2); |
|||
} |
|||
else { |
|||
var texts = text.split("e"); |
|||
if (texts.length > 2) throw new Error("Invalid integer"); |
|||
if (texts[1]) { |
|||
var exp = texts[1]; |
|||
if (exp[0] === "+") exp = exp.slice(1); |
|||
exp = parse(exp); |
|||
if (exp.lesser(0)) throw new Error("Cannot include negative exponent part for integers"); |
|||
while (exp.notEquals(0)) { |
|||
texts[0] += "0"; |
|||
exp = exp.prev(); |
|||
} |
|||
} |
|||
text = texts[0]; |
|||
} |
|||
if (text === "-0") text = "0"; |
|||
text = text.toUpperCase(); |
|||
var isValid = (base == 16 ? /^[0-9A-F]*$/ : /^[0-9]+$/).test(text); |
|||
if (!isValid) throw new Error("Invalid integer"); |
|||
if (base == 16) { |
|||
var val = bigInt(0); |
|||
while (text.length) { |
|||
v = text.charCodeAt(0) - 48; |
|||
if (v > 9) |
|||
v -= 7; |
|||
text = text.slice(1); |
|||
val = val.times(16).plus(v); |
|||
} |
|||
return val; |
|||
} |
|||
else { |
|||
while (text.length) { |
|||
var divider = text.length > logBase ? text.length - logBase : 0; |
|||
value.push(+text.slice(divider)); |
|||
text = text.slice(0, divider); |
|||
} |
|||
var val = bigInt(value, s); |
|||
if (first) normalize(first, val); |
|||
return val; |
|||
} |
|||
}; |
|||
|
|||
var goesInto = function (a, b) { |
|||
var a = bigInt(a, sign.positive), b = bigInt(b, sign.positive); |
|||
if (a.equals(0)) throw new Error("Cannot divide by 0"); |
|||
var n = 0; |
|||
do { |
|||
var inc = 1; |
|||
var c = bigInt(a.value, sign.positive), t = c.times(10); |
|||
while (t.lesser(b)) { |
|||
c = t; |
|||
inc *= 10; |
|||
t = t.times(10); |
|||
} |
|||
while (c.lesserOrEquals(b)) { |
|||
b = b.minus(c); |
|||
n += inc; |
|||
} |
|||
} while (a.lesserOrEquals(b)); |
|||
|
|||
return { |
|||
remainder: b.value, |
|||
result: n |
|||
}; |
|||
}; |
|||
|
|||
var bigInt = function (value, s) { |
|||
var self = { |
|||
value: value, |
|||
sign: s |
|||
}; |
|||
var o = { |
|||
value: value, |
|||
sign: s, |
|||
negate: function (m) { |
|||
var first = m || self; |
|||
return bigInt(first.value, !first.sign); |
|||
}, |
|||
abs: function (m) { |
|||
var first = m || self; |
|||
return bigInt(first.value, sign.positive); |
|||
}, |
|||
add: function (n, m) { |
|||
var s, first = self, second; |
|||
if (m) (first = parse(n)) && (second = parse(m)); |
|||
else second = parse(n, first); |
|||
s = first.sign; |
|||
if (first.sign !== second.sign) { |
|||
first = bigInt(first.value, sign.positive); |
|||
second = bigInt(second.value, sign.positive); |
|||
return s === sign.positive ? |
|||
o.subtract(first, second) : |
|||
o.subtract(second, first); |
|||
} |
|||
normalize(first, second); |
|||
var a = first.value, b = second.value; |
|||
var result = [], |
|||
carry = 0; |
|||
for (var i = 0; i < a.length || carry > 0; i++) { |
|||
var sum = (a[i] || 0) + (b[i] || 0) + carry; |
|||
carry = sum >= base ? 1 : 0; |
|||
sum -= carry * base; |
|||
result.push(sum); |
|||
} |
|||
return bigInt(result, s); |
|||
}, |
|||
plus: function (n, m) { |
|||
return o.add(n, m); |
|||
}, |
|||
subtract: function (n, m) { |
|||
var first = self, second; |
|||
if (m) (first = parse(n)) && (second = parse(m)); |
|||
else second = parse(n, first); |
|||
if (first.sign !== second.sign) return o.add(first, o.negate(second)); |
|||
if (first.sign === sign.negative) return o.subtract(o.negate(second), o.negate(first)); |
|||
if (o.compare(first, second) === -1) return o.negate(o.subtract(second, first)); |
|||
var a = first.value, b = second.value; |
|||
var result = [], |
|||
borrow = 0; |
|||
for (var i = 0; i < a.length; i++) { |
|||
var tmp = a[i] - borrow; |
|||
borrow = tmp < b[i] ? 1 : 0; |
|||
var minuend = (borrow * base) + tmp - b[i]; |
|||
result.push(minuend); |
|||
} |
|||
return bigInt(result, sign.positive); |
|||
}, |
|||
minus: function (n, m) { |
|||
return o.subtract(n, m); |
|||
}, |
|||
multiply: function (n, m) { |
|||
var s, first = self, second; |
|||
if (m) (first = parse(n)) && (second = parse(m)); |
|||
else second = parse(n, first); |
|||
s = first.sign !== second.sign; |
|||
var a = first.value, b = second.value; |
|||
var resultSum = []; |
|||
for (var i = 0; i < a.length; i++) { |
|||
resultSum[i] = []; |
|||
var j = i; |
|||
while (j--) { |
|||
resultSum[i].push(0); |
|||
} |
|||
} |
|||
var carry = 0; |
|||
for (var i = 0; i < a.length; i++) { |
|||
var x = a[i]; |
|||
for (var j = 0; j < b.length || carry > 0; j++) { |
|||
var y = b[j]; |
|||
var product = y ? (x * y) + carry : carry; |
|||
carry = product > base ? Math.floor(product / base) : 0; |
|||
product -= carry * base; |
|||
resultSum[i].push(product); |
|||
} |
|||
} |
|||
var max = -1; |
|||
for (var i = 0; i < resultSum.length; i++) { |
|||
var len = resultSum[i].length; |
|||
if (len > max) max = len; |
|||
} |
|||
var result = [], carry = 0; |
|||
for (var i = 0; i < max || carry > 0; i++) { |
|||
var sum = carry; |
|||
for (var j = 0; j < resultSum.length; j++) { |
|||
sum += resultSum[j][i] || 0; |
|||
} |
|||
carry = sum > base ? Math.floor(sum / base) : 0; |
|||
sum -= carry * base; |
|||
result.push(sum); |
|||
} |
|||
return bigInt(result, s); |
|||
}, |
|||
times: function (n, m) { |
|||
return o.multiply(n, m); |
|||
}, |
|||
divmod: function (n, m) { |
|||
var s, first = self, second; |
|||
if (m) (first = parse(n)) && (second = parse(m)); |
|||
else second = parse(n, first); |
|||
s = first.sign !== second.sign; |
|||
if (bigInt(first.value, first.sign).equals(0)) return { |
|||
quotient: bigInt([0], sign.positive), |
|||
remainder: bigInt([0], sign.positive) |
|||
}; |
|||
if (second.equals(0)) throw new Error("Cannot divide by zero"); |
|||
var a = first.value, b = second.value; |
|||
var result = [], remainder = []; |
|||
for (var i = a.length - 1; i >= 0; i--) { |
|||
var n = [a[i]].concat(remainder); |
|||
var quotient = goesInto(b, n); |
|||
result.push(quotient.result); |
|||
remainder = quotient.remainder; |
|||
} |
|||
result.reverse(); |
|||
return { |
|||
quotient: bigInt(result, s), |
|||
remainder: bigInt(remainder, first.sign) |
|||
}; |
|||
}, |
|||
divide: function (n, m) { |
|||
return o.divmod(n, m).quotient; |
|||
}, |
|||
over: function (n, m) { |
|||
return o.divide(n, m); |
|||
}, |
|||
mod: function (n, m) { |
|||
return o.divmod(n, m).remainder; |
|||
}, |
|||
pow: function (n, m) { |
|||
var first = self, second; |
|||
if (m) (first = parse(n)) && (second = parse(m)); |
|||
else second = parse(n, first); |
|||
var a = first, b = second; |
|||
if (b.lesser(0)) return ZERO; |
|||
if (b.equals(0)) return ONE; |
|||
var result = bigInt(a.value, a.sign); |
|||
|
|||
if (b.mod(2).equals(0)) { |
|||
var c = result.pow(b.over(2)); |
|||
return c.times(c); |
|||
} else { |
|||
return result.times(result.pow(b.minus(1))); |
|||
} |
|||
}, |
|||
next: function (m) { |
|||
var first = m || self; |
|||
return o.add(first, 1); |
|||
}, |
|||
prev: function (m) { |
|||
var first = m || self; |
|||
return o.subtract(first, 1); |
|||
}, |
|||
compare: function (n, m) { |
|||
var first = self, second; |
|||
if (m) (first = parse(n)) && (second = parse(m, first)); |
|||
else second = parse(n, first); |
|||
normalize(first, second); |
|||
if (first.value.length === 1 && second.value.length === 1 && first.value[0] === 0 && second.value[0] === 0) return 0; |
|||
if (second.sign !== first.sign) return first.sign === sign.positive ? 1 : -1; |
|||
var multiplier = first.sign === sign.positive ? 1 : -1; |
|||
var a = first.value, b = second.value; |
|||
for (var i = a.length - 1; i >= 0; i--) { |
|||
if (a[i] > b[i]) return 1 * multiplier; |
|||
if (b[i] > a[i]) return -1 * multiplier; |
|||
} |
|||
return 0; |
|||
}, |
|||
compareAbs: function (n, m) { |
|||
var first = self, second; |
|||
if (m) (first = parse(n)) && (second = parse(m, first)); |
|||
else second = parse(n, first); |
|||
first.sign = second.sign = sign.positive; |
|||
return o.compare(first, second); |
|||
}, |
|||
equals: function (n, m) { |
|||
return o.compare(n, m) === 0; |
|||
}, |
|||
notEquals: function (n, m) { |
|||
return !o.equals(n, m); |
|||
}, |
|||
lesser: function (n, m) { |
|||
return o.compare(n, m) < 0; |
|||
}, |
|||
greater: function (n, m) { |
|||
return o.compare(n, m) > 0; |
|||
}, |
|||
greaterOrEquals: function (n, m) { |
|||
return o.compare(n, m) >= 0; |
|||
}, |
|||
lesserOrEquals: function (n, m) { |
|||
return o.compare(n, m) <= 0; |
|||
}, |
|||
isPositive: function (m) { |
|||
var first = m || self; |
|||
return first.sign === sign.positive; |
|||
}, |
|||
isNegative: function (m) { |
|||
var first = m || self; |
|||
return first.sign === sign.negative; |
|||
}, |
|||
isEven: function (m) { |
|||
var first = m || self; |
|||
return first.value[0] % 2 === 0; |
|||
}, |
|||
isOdd: function (m) { |
|||
var first = m || self; |
|||
return first.value[0] % 2 === 1; |
|||
}, |
|||
toString: function (m) { |
|||
var first = m || self; |
|||
var str = "", len = first.value.length; |
|||
while (len--) { |
|||
if (first.value[len].toString().length === 8) str += first.value[len]; |
|||
else str += (base.toString() + first.value[len]).slice(-logBase); |
|||
} |
|||
while (str[0] === "0") { |
|||
str = str.slice(1); |
|||
} |
|||
if (!str.length) str = "0"; |
|||
var s = (first.sign === sign.positive || str == "0") ? "" : "-"; |
|||
return s + str; |
|||
}, |
|||
toHex: function (m) { |
|||
var first = m || self; |
|||
var str = ""; |
|||
var l = this.abs(); |
|||
while (l > 0) { |
|||
var qr = l.divmod(256); |
|||
var b = qr.remainder.toJSNumber(); |
|||
str = (b >> 4).toString(16) + (b & 15).toString(16) + str; |
|||
l = qr.quotient; |
|||
} |
|||
return (this.isNegative() ? "-" : "") + "0x" + str; |
|||
}, |
|||
toJSNumber: function (m) { |
|||
return +o.toString(m); |
|||
}, |
|||
valueOf: function (m) { |
|||
return o.toJSNumber(m); |
|||
} |
|||
}; |
|||
return o; |
|||
}; |
|||
|
|||
var ZERO = bigInt([0], sign.positive); |
|||
var ONE = bigInt([1], sign.positive); |
|||
var MINUS_ONE = bigInt([1], sign.negative); |
|||
|
|||
var fnReturn = function (a) { |
|||
if (typeof a === "undefined") return ZERO; |
|||
return parse(a); |
|||
}; |
|||
fnReturn.zero = ZERO; |
|||
fnReturn.one = ONE; |
|||
fnReturn.minusOne = MINUS_ONE; |
|||
return fnReturn; |
|||
})(); |
|||
|
|||
if (typeof module !== "undefined") { |
|||
module.exports = bigInt; |
|||
} |
@ -0,0 +1,65 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file CommonJS.cpp
|
|||
* @authors: |
|||
* Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "CommonJS.h" |
|||
using namespace std; |
|||
using namespace eth; |
|||
|
|||
bytes eth::jsToBytes(string const& _s) |
|||
{ |
|||
if (_s.substr(0, 2) == "0x") |
|||
// Hex
|
|||
return fromHex(_s.substr(2)); |
|||
else if (_s.find_first_not_of("0123456789") == string::npos) |
|||
// Decimal
|
|||
return toCompactBigEndian(bigint(_s)); |
|||
else |
|||
// Binary
|
|||
return asBytes(_s); |
|||
} |
|||
|
|||
string eth::jsPadded(string const& _s, unsigned _l, unsigned _r) |
|||
{ |
|||
bytes b = jsToBytes(_s); |
|||
while (b.size() < _l) |
|||
b.insert(b.begin(), 0); |
|||
while (b.size() < _r) |
|||
b.push_back(0); |
|||
return asString(b).substr(b.size() - max(_l, _r)); |
|||
} |
|||
|
|||
string eth::jsPadded(string const& _s, unsigned _l) |
|||
{ |
|||
if (_s.substr(0, 2) == "0x" || _s.find_first_not_of("0123456789") == string::npos) |
|||
// Numeric: pad to right
|
|||
return jsPadded(_s, _l, _l); |
|||
else |
|||
// Text: pad to the left
|
|||
return jsPadded(_s, 0, _l); |
|||
} |
|||
|
|||
string eth::jsUnpadded(string _s) |
|||
{ |
|||
auto p = _s.find_last_not_of((char)0); |
|||
_s.resize(p == string::npos ? 0 : (p + 1)); |
|||
return _s; |
|||
} |
@ -0,0 +1,88 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file CommonJS.h
|
|||
* @authors: |
|||
* Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
#include <libethential/Common.h> |
|||
#include <libethential/CommonIO.h> |
|||
#include <libethential/CommonData.h> |
|||
#include <libethential/FixedHash.h> |
|||
#include <libethcore/CommonEth.h> |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
eth::bytes jsToBytes(std::string const& _s); |
|||
std::string jsPadded(std::string const& _s, unsigned _l, unsigned _r); |
|||
std::string jsPadded(std::string const& _s, unsigned _l); |
|||
std::string jsUnpadded(std::string _s); |
|||
|
|||
template <unsigned N> eth::FixedHash<N> jsToFixed(std::string const& _s) |
|||
{ |
|||
if (_s.substr(0, 2) == "0x") |
|||
// Hex
|
|||
return eth::FixedHash<N>(_s.substr(2)); |
|||
else if (_s.find_first_not_of("0123456789") == std::string::npos) |
|||
// Decimal
|
|||
return (typename eth::FixedHash<N>::Arith)(_s); |
|||
else |
|||
// Binary
|
|||
return eth::FixedHash<N>(asBytes(jsPadded(_s, N))); |
|||
} |
|||
|
|||
template <unsigned N> boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> jsToInt(std::string const& _s) |
|||
{ |
|||
if (_s.substr(0, 2) == "0x") |
|||
// Hex
|
|||
return eth::fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(eth::fromHex(_s.substr(2))); |
|||
else if (_s.find_first_not_of("0123456789") == std::string::npos) |
|||
// Decimal
|
|||
return boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>(_s); |
|||
else |
|||
// Binary
|
|||
return eth::fromBigEndian<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N * 8, N * 8, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>>(asBytes(jsPadded(_s, N))); |
|||
} |
|||
|
|||
inline eth::Address jsToAddress(std::string const& _s) { return jsToFixed<20>(_s); } |
|||
inline eth::Secret jsToSecret(std::string const& _s) { return jsToFixed<32>(_s); } |
|||
inline eth::u256 jsToU256(std::string const& _s) { return jsToInt<32>(_s); } |
|||
|
|||
template <unsigned S> std::string toJS(eth::FixedHash<S> const& _h) { return "0x" + toHex(_h.ref()); } |
|||
template <unsigned N> std::string toJS(boost::multiprecision::number<boost::multiprecision::cpp_int_backend<N, N, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>> const& _n) { return "0x" + eth::toHex(eth::toCompactBigEndian(_n)); } |
|||
|
|||
inline std::string jsToBinary(std::string const& _s) |
|||
{ |
|||
return eth::asString(jsToBytes(_s)); |
|||
} |
|||
|
|||
inline std::string jsToDecimal(std::string const& _s) |
|||
{ |
|||
return eth::toString(jsToU256(_s)); |
|||
} |
|||
|
|||
inline std::string jsToHex(std::string const& _s) |
|||
{ |
|||
return "0x" + eth::toHex(asBytes(_s)); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,212 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file EthStubServer.cpp
|
|||
* @authors: |
|||
* Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#if ETH_JSONRPC |
|||
#include "EthStubServer.h" |
|||
#include <libevmface/Instruction.h> |
|||
#include <liblll/Compiler.h> |
|||
#include <libethereum/Client.h> |
|||
#include "CommonJS.h" |
|||
using namespace std; |
|||
using namespace eth; |
|||
|
|||
EthStubServer::EthStubServer(jsonrpc::AbstractServerConnector* _conn, Client& _client): |
|||
AbstractEthStubServer(_conn), |
|||
m_client(_client) |
|||
{ |
|||
} |
|||
|
|||
//only works with a json spec that doesn't have notifications for now
|
|||
Json::Value EthStubServer::procedures() |
|||
{ |
|||
Json::Value ret; |
|||
|
|||
for (auto proc: this->GetProtocolHanlder()->GetProcedures()) |
|||
{ |
|||
Json::Value proc_j; |
|||
|
|||
proc_j[proc.second->GetProcedureType() == 0 ? "method" : "notification"] = proc.first; |
|||
|
|||
Json::Value params_j; |
|||
for (auto params: proc.second->GetParameters()) |
|||
params_j[params.first] = jsontypeToValue(params.second); |
|||
proc_j["params"] = params_j; |
|||
|
|||
proc_j["returns"] = jsontypeToValue(proc.second->GetReturnType()); |
|||
|
|||
ret.append(proc_j); |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
std::string EthStubServer::coinbase() |
|||
{ |
|||
ClientGuard g(&m_client); |
|||
return toJS(m_client.address()); |
|||
} |
|||
|
|||
std::string EthStubServer::balanceAt(std::string const& _a) |
|||
{ |
|||
ClientGuard g(&m_client); |
|||
return toJS(m_client.postState().balance(jsToAddress(_a))); |
|||
} |
|||
|
|||
Json::Value EthStubServer::check(Json::Value const& _as) |
|||
{ |
|||
if (m_client.changed()) |
|||
return _as; |
|||
else |
|||
{ |
|||
Json::Value ret; |
|||
ret.resize(0); |
|||
return ret; |
|||
} |
|||
} |
|||
|
|||
std::string EthStubServer::create(const std::string& _bCode, const std::string& _sec, const std::string& _xEndowment, const std::string& _xGas, const std::string& _xGasPrice) |
|||
{ |
|||
ClientGuard g(&m_client); |
|||
Address ret = m_client.transact(jsToSecret(_sec), jsToU256(_xEndowment), jsToBytes(_bCode), jsToU256(_xGas), jsToU256(_xGasPrice)); |
|||
return toJS(ret); |
|||
} |
|||
|
|||
std::string EthStubServer::lll(const std::string& _s) |
|||
{ |
|||
return "0x" + toHex(eth::compileLLL(_s)); |
|||
} |
|||
|
|||
std::string EthStubServer::gasPrice() |
|||
{ |
|||
return "100000000000000"; |
|||
} |
|||
|
|||
bool EthStubServer::isContractAt(const std::string& _a) |
|||
{ |
|||
ClientGuard g(&m_client); |
|||
return m_client.postState().addressHasCode(jsToAddress(_a)); |
|||
} |
|||
|
|||
bool EthStubServer::isListening() |
|||
{ |
|||
return m_client.haveNetwork(); |
|||
} |
|||
|
|||
bool EthStubServer::isMining() |
|||
{ |
|||
return m_client.isMining(); |
|||
} |
|||
|
|||
std::string EthStubServer::key() |
|||
{ |
|||
if (!m_keys.size()) |
|||
return std::string(); |
|||
return toJS(m_keys[0].sec()); |
|||
} |
|||
|
|||
Json::Value EthStubServer::keys() |
|||
{ |
|||
Json::Value ret; |
|||
for (auto i: m_keys) |
|||
ret.append(toJS(i.secret())); |
|||
return ret; |
|||
} |
|||
|
|||
int EthStubServer::peerCount() |
|||
{ |
|||
ClientGuard g(&m_client); |
|||
return m_client.peerCount(); |
|||
} |
|||
|
|||
std::string EthStubServer::storageAt(const std::string& _a, const std::string& x) |
|||
{ |
|||
ClientGuard g(&m_client); |
|||
return toJS(m_client.postState().storage(jsToAddress(_a), jsToU256(x))); |
|||
} |
|||
|
|||
Json::Value EthStubServer::transact(const std::string& _aDest, const std::string& _bData, const std::string& _sec, const std::string& _xGas, const std::string& _xGasPrice, const std::string& _xValue) |
|||
{ |
|||
ClientGuard g(&m_client); |
|||
m_client.transact(jsToSecret(_sec), jsToU256(_xValue), jsToAddress(_aDest), jsToBytes(_bData), jsToU256(_xGas), jsToU256(_xGasPrice)); |
|||
return Json::Value(); |
|||
} |
|||
|
|||
std::string EthStubServer::txCountAt(const std::string& _a) |
|||
{ |
|||
ClientGuard g(&m_client); |
|||
return toJS(m_client.postState().transactionsFrom(jsToAddress(_a))); |
|||
} |
|||
|
|||
std::string EthStubServer::secretToAddress(const std::string& _a) |
|||
{ |
|||
return toJS(KeyPair(jsToSecret(_a)).address()); |
|||
} |
|||
|
|||
Json::Value EthStubServer::lastBlock() |
|||
{ |
|||
return blockJson(""); |
|||
} |
|||
|
|||
Json::Value EthStubServer::block(const std::string& _hash) |
|||
{ |
|||
return blockJson(_hash); |
|||
} |
|||
|
|||
Json::Value EthStubServer::blockJson(const std::string& _hash) |
|||
{ |
|||
Json::Value res; |
|||
auto const& bc = m_client.blockChain(); |
|||
|
|||
auto b = _hash.length() ? bc.block(h256(_hash)) : bc.block(); |
|||
|
|||
auto bi = BlockInfo(b); |
|||
res["number"] = to_string(bc.details(bc.currentHash()).number); |
|||
res["hash"] = boost::lexical_cast<string>(bi.hash); |
|||
res["parentHash"] = boost::lexical_cast<string>(bi.parentHash); |
|||
res["sha3Uncles"] = boost::lexical_cast<string>(bi.sha3Uncles); |
|||
res["coinbaseAddress"] = boost::lexical_cast<string>(bi.coinbaseAddress); |
|||
res["stateRoot"] = boost::lexical_cast<string>(bi.stateRoot); |
|||
res["transactionsRoot"] = boost::lexical_cast<string>(bi.transactionsRoot); |
|||
res["minGasPrice"] = boost::lexical_cast<string>(bi.minGasPrice); |
|||
res["gasLimit"] = boost::lexical_cast<string>(bi.gasLimit); |
|||
res["gasUsed"] = boost::lexical_cast<string>(bi.gasUsed); |
|||
res["difficulty"] = boost::lexical_cast<string>(bi.difficulty); |
|||
res["timestamp"] = boost::lexical_cast<string>(bi.timestamp); |
|||
res["nonce"] = boost::lexical_cast<string>(bi.nonce); |
|||
|
|||
return res; |
|||
} |
|||
|
|||
Json::Value EthStubServer::jsontypeToValue(int _jsontype) |
|||
{ |
|||
switch (_jsontype) |
|||
{ |
|||
case jsonrpc::JSON_STRING: return ""; //Json::stringValue segfault, fuck knows why
|
|||
case jsonrpc::JSON_BOOLEAN: return Json::booleanValue; |
|||
case jsonrpc::JSON_INTEGER: return Json::intValue; |
|||
case jsonrpc::JSON_REAL: return Json::realValue; |
|||
case jsonrpc::JSON_OBJECT: return Json::objectValue; |
|||
case jsonrpc::JSON_ARRAY: return Json::arrayValue; |
|||
default: return Json::nullValue; |
|||
} |
|||
} |
|||
|
|||
#endif |
@ -0,0 +1,64 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file EthStubServer.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <iostream> |
|||
#include <jsonrpc/rpc.h> |
|||
#pragma GCC diagnostic push |
|||
#pragma GCC diagnostic ignored "-Wunused-parameter" |
|||
#include "abstractethstubserver.h" |
|||
#pragma GCC diagnostic pop |
|||
|
|||
namespace eth { class Client; } |
|||
namespace eth { class KeyPair; } |
|||
|
|||
class EthStubServer: public AbstractEthStubServer |
|||
{ |
|||
public: |
|||
EthStubServer(jsonrpc::AbstractServerConnector* _conn, eth::Client& _client); |
|||
|
|||
virtual Json::Value procedures(); |
|||
virtual std::string balanceAt(std::string const& _a); |
|||
virtual Json::Value check(Json::Value const& _as); |
|||
virtual std::string coinbase(); |
|||
virtual std::string create(const std::string& bCode, const std::string& sec, const std::string& xEndowment, const std::string& xGas, const std::string& xGasPrice); |
|||
virtual std::string gasPrice(); |
|||
virtual bool isContractAt(const std::string& a); |
|||
virtual bool isListening(); |
|||
virtual bool isMining(); |
|||
virtual std::string key(); |
|||
virtual Json::Value keys(); |
|||
virtual int peerCount(); |
|||
virtual std::string storageAt(const std::string& a, const std::string& x); |
|||
virtual Json::Value transact(const std::string& aDest, const std::string& bData, const std::string& sec, const std::string& xGas, const std::string& xGasPrice, const std::string& xValue); |
|||
virtual std::string txCountAt(const std::string& a); |
|||
virtual std::string secretToAddress(const std::string& a); |
|||
virtual Json::Value lastBlock(); |
|||
virtual std::string lll(const std::string& s); |
|||
virtual Json::Value block(const std::string&); |
|||
void setKeys(std::vector<eth::KeyPair> _keys) { m_keys = _keys; } |
|||
private: |
|||
eth::Client& m_client; |
|||
std::vector<eth::KeyPair> m_keys; |
|||
Json::Value jsontypeToValue(int); |
|||
Json::Value blockJson(const std::string&); |
|||
}; |
@ -0,0 +1,155 @@ |
|||
/**
|
|||
* THIS FILE IS GENERATED BY jsonrpcstub, DO NOT CHANGE IT!!!!! |
|||
*/ |
|||
|
|||
#ifndef _ABSTRACTETHSTUBSERVER_H_ |
|||
#define _ABSTRACTETHSTUBSERVER_H_ |
|||
|
|||
#include <jsonrpc/rpc.h> |
|||
|
|||
class AbstractEthStubServer : public jsonrpc::AbstractServer<AbstractEthStubServer> |
|||
{ |
|||
public: |
|||
AbstractEthStubServer(jsonrpc::AbstractServerConnector* conn) : |
|||
jsonrpc::AbstractServer<AbstractEthStubServer>(conn) |
|||
{ |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("balanceAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::balanceAtI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("block", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::blockI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("check", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY, "a",jsonrpc::JSON_ARRAY, NULL), &AbstractEthStubServer::checkI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("coinbase", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::coinbaseI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("create", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "bCode",jsonrpc::JSON_STRING,"sec",jsonrpc::JSON_STRING,"xEndowment",jsonrpc::JSON_STRING,"xGas",jsonrpc::JSON_STRING,"xGasPrice",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::createI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("gasPrice", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::gasPriceI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("isContractAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_BOOLEAN, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::isContractAtI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("isListening", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_BOOLEAN, NULL), &AbstractEthStubServer::isListeningI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("isMining", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_BOOLEAN, NULL), &AbstractEthStubServer::isMiningI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("key", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::keyI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("keys", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY, NULL), &AbstractEthStubServer::keysI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("lastBlock", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT, NULL), &AbstractEthStubServer::lastBlockI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("lll", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "s",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::lllI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("peerCount", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_INTEGER, NULL), &AbstractEthStubServer::peerCountI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("procedures", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY, NULL), &AbstractEthStubServer::proceduresI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("secretToAddress", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::secretToAddressI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("storageAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING,"x",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::storageAtI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("transact", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT, "aDest",jsonrpc::JSON_STRING,"bData",jsonrpc::JSON_STRING,"sec",jsonrpc::JSON_STRING,"xGas",jsonrpc::JSON_STRING,"xGasPrice",jsonrpc::JSON_STRING,"xValue",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::transactI); |
|||
this->bindAndAddMethod(new jsonrpc::Procedure("txCountAt", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_STRING, "a",jsonrpc::JSON_STRING, NULL), &AbstractEthStubServer::txCountAtI); |
|||
|
|||
} |
|||
|
|||
inline virtual void balanceAtI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->balanceAt(request["a"].asString()); |
|||
} |
|||
|
|||
inline virtual void blockI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->block(request["a"].asString()); |
|||
} |
|||
|
|||
inline virtual void checkI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->check(request["a"]); |
|||
} |
|||
|
|||
inline virtual void coinbaseI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->coinbase(); |
|||
} |
|||
|
|||
inline virtual void createI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->create(request["bCode"].asString(), request["sec"].asString(), request["xEndowment"].asString(), request["xGas"].asString(), request["xGasPrice"].asString()); |
|||
} |
|||
|
|||
inline virtual void gasPriceI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->gasPrice(); |
|||
} |
|||
|
|||
inline virtual void isContractAtI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->isContractAt(request["a"].asString()); |
|||
} |
|||
|
|||
inline virtual void isListeningI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->isListening(); |
|||
} |
|||
|
|||
inline virtual void isMiningI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->isMining(); |
|||
} |
|||
|
|||
inline virtual void keyI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->key(); |
|||
} |
|||
|
|||
inline virtual void keysI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->keys(); |
|||
} |
|||
|
|||
inline virtual void lastBlockI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->lastBlock(); |
|||
} |
|||
|
|||
inline virtual void lllI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->lll(request["s"].asString()); |
|||
} |
|||
|
|||
inline virtual void peerCountI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->peerCount(); |
|||
} |
|||
|
|||
inline virtual void proceduresI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->procedures(); |
|||
} |
|||
|
|||
inline virtual void secretToAddressI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->secretToAddress(request["a"].asString()); |
|||
} |
|||
|
|||
inline virtual void storageAtI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->storageAt(request["a"].asString(), request["x"].asString()); |
|||
} |
|||
|
|||
inline virtual void transactI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->transact(request["aDest"].asString(), request["bData"].asString(), request["sec"].asString(), request["xGas"].asString(), request["xGasPrice"].asString(), request["xValue"].asString()); |
|||
} |
|||
|
|||
inline virtual void txCountAtI(const Json::Value& request, Json::Value& response) |
|||
{ |
|||
response = this->txCountAt(request["a"].asString()); |
|||
} |
|||
|
|||
|
|||
virtual std::string balanceAt(const std::string& a) = 0; |
|||
virtual Json::Value block(const std::string& a) = 0; |
|||
virtual Json::Value check(const Json::Value& a) = 0; |
|||
virtual std::string coinbase() = 0; |
|||
virtual std::string create(const std::string& bCode, const std::string& sec, const std::string& xEndowment, const std::string& xGas, const std::string& xGasPrice) = 0; |
|||
virtual std::string gasPrice() = 0; |
|||
virtual bool isContractAt(const std::string& a) = 0; |
|||
virtual bool isListening() = 0; |
|||
virtual bool isMining() = 0; |
|||
virtual std::string key() = 0; |
|||
virtual Json::Value keys() = 0; |
|||
virtual Json::Value lastBlock() = 0; |
|||
virtual std::string lll(const std::string& s) = 0; |
|||
virtual int peerCount() = 0; |
|||
virtual Json::Value procedures() = 0; |
|||
virtual std::string secretToAddress(const std::string& a) = 0; |
|||
virtual std::string storageAt(const std::string& a, const std::string& x) = 0; |
|||
virtual Json::Value transact(const std::string& aDest, const std::string& bData, const std::string& sec, const std::string& xGas, const std::string& xGasPrice, const std::string& xValue) = 0; |
|||
virtual std::string txCountAt(const std::string& a) = 0; |
|||
|
|||
}; |
|||
#endif //_ABSTRACTETHSTUBSERVER_H_
|
@ -0,0 +1,131 @@ |
|||
if (typeof(window.eth) === "undefined") |
|||
{ |
|||
if (typeof(require) !== "undefined") |
|||
require( ['ethString'], function() {} ) |
|||
else if (typeof(String.prototype.pad) === "undefined") |
|||
{ |
|||
var scriptTag = document.getElementsByTagName('script'); |
|||
scriptTag = scriptTag[scriptTag.length - 1]; |
|||
var scriptPath = scriptTag.src; |
|||
var path = scriptPath.substr(0, scriptPath.lastIndexOf( '/' )); |
|||
var start = '<script src="' + path + '/'; |
|||
var slash = '"><'+'/script>'; |
|||
document.write(start + 'BigInteger.js' + slash); |
|||
document.write(start + 'ethString.js' + slash); |
|||
} |
|||
|
|||
var spec = [ |
|||
{ "method": "procedures", "params": null, "order": [], "returns": [] }, |
|||
{ "method": "coinbase", "params": null, "order": [], "returns" : "" }, |
|||
{ "method": "isListening", "params": null, "order": [], "returns" : false }, |
|||
{ "method": "isMining", "params": null, "order": [], "returns" : false }, |
|||
{ "method": "gasPrice", "params": null, "order": [], "returns" : "" }, |
|||
{ "method": "key", "params": null, "order": [], "returns" : "" }, |
|||
{ "method": "keys", "params": null, "order": [], "returns" : [] }, |
|||
{ "method": "peerCount", "params": null, "order": [], "returns" : 0 }, |
|||
{ "method": "balanceAt", "params": { "a": "" }, "order": ["a"], "returns" : "" }, |
|||
{ "method": "storageAt", "params": { "a": "", "x": "" }, "order": ["a", "x"], "returns" : "" }, |
|||
{ "method": "txCountAt", "params": { "a": "" },"order": ["a"], "returns" : "" }, |
|||
{ "method": "isContractAt", "params": { "a": "" }, "order": ["a"], "returns" : false }, |
|||
{ "method": "create", "params": { "sec": "", "xEndowment": "", "bCode": "", "xGas": "", "xGasPrice": "" }, "order": ["sec", "xEndowment", "bCode", "xGas", "xGasPrice"] , "returns": "" }, |
|||
{ "method": "transact", "params": { "sec": "", "xValue": "", "aDest": "", "bData": "", "xGas": "", "xGasPrice": "" }, "order": ["sec", "xValue", "aDest", "bData", "xGas", "xGasPrice"], "returns": {} }, |
|||
{ "method": "secretToAddress", "params": { "a": "" }, "order": ["a"], "returns" : "" }, |
|||
{ "method": "lll", "params": { "s": "" }, "order": ["s"], "returns" : "" } |
|||
]; |
|||
|
|||
window.eth = (function ethScope() { |
|||
var m_reqId = 0 |
|||
var ret = {} |
|||
function reformat(m, d) { return m == "lll" ? d.bin() : d; } |
|||
function reqSync(m, p) { |
|||
var req = { "jsonrpc": "2.0", "method": m, "params": p, "id": m_reqId } |
|||
m_reqId++ |
|||
var request = new XMLHttpRequest(); |
|||
request.open("POST", "http://localhost:8080", false) |
|||
// console.log("Sending " + JSON.stringify(req))
|
|||
request.send(JSON.stringify(req)) |
|||
return reformat(m, JSON.parse(request.responseText).result) |
|||
} |
|||
function reqAsync(m, p, f) { |
|||
var req = { "jsonrpc": "2.0", "method": m, "params": p, "id": m_reqId } |
|||
m_reqId++ |
|||
var request = new XMLHttpRequest(); |
|||
request.open("POST", "http://localhost:8080", true) |
|||
request.send(JSON.stringify(req)) |
|||
request.onreadystatechange = function() { |
|||
if (request.readyState === 4) |
|||
f(reformat(m, JSON.parse(request.responseText).result)) |
|||
}; |
|||
} |
|||
function isEmpty(obj) { |
|||
for (var prop in obj) |
|||
if (obj.hasOwnProperty(prop)) |
|||
return false |
|||
return true |
|||
} |
|||
|
|||
var m_watching = {}; |
|||
|
|||
for (si in spec) (function(s) { |
|||
var m = s.method; |
|||
var am = "get" + m.slice(0, 1).toUpperCase() + m.slice(1); |
|||
var getParams = function(a) { |
|||
var p = s.params ? {} : null |
|||
for (j in s.order) |
|||
p[s.order[j]] = (s.order[j][0] === "b") ? a[j].unbin() : a[j] |
|||
return p |
|||
}; |
|||
if (m == "create" || m == "transact") |
|||
ret[m] = function() { return reqAsync(m, getParams(arguments), arguments[s.order.length]) } |
|||
else |
|||
{ |
|||
ret[am] = function() { return reqAsync(m, getParams(arguments), arguments[s.order.length]) } |
|||
if (s.params) |
|||
ret[m] = function() { return reqSync(m, getParams(arguments)) } |
|||
else |
|||
Object.defineProperty(ret, m, { |
|||
get: function() { return reqSync(m, {}); }, |
|||
set: function(v) {} |
|||
}) |
|||
} |
|||
})(spec[si]); |
|||
|
|||
ret.check = function(force) { |
|||
if (!force && isEmpty(m_watching)) |
|||
return |
|||
var watching = []; |
|||
for (var w in m_watching) |
|||
watching.push(w) |
|||
var changed = reqSync("check", { "a": watching } ); |
|||
// console.log("Got " + JSON.stringify(changed));
|
|||
for (var c in changed) |
|||
m_watching[changed[c]]() |
|||
var that = this; |
|||
setTimeout(function() { that.check() }, 5000) |
|||
} |
|||
|
|||
ret.watch = function(a, fx, f) { |
|||
var old = isEmpty(m_watching) |
|||
if (f) |
|||
m_watching[a + fx] = f |
|||
else |
|||
m_watching[a] = fx |
|||
(f ? f : fx)() |
|||
if (isEmpty(m_watching) != old) |
|||
this.check() |
|||
} |
|||
ret.unwatch = function(f, fx) { |
|||
delete m_watching[fx ? f + fx : f]; |
|||
} |
|||
ret.newBlock = function(f) { |
|||
var old = isEmpty(m_watching) |
|||
m_watching[""] = f |
|||
f() |
|||
if (isEmpty(m_watching) != old) |
|||
this.check() |
|||
} |
|||
return ret; |
|||
}()); |
|||
|
|||
} |
|||
|
@ -0,0 +1,62 @@ |
|||
if (typeof(require) !== "undefined") |
|||
require( ['BigInteger'], function() {} ) |
|||
else if (typeof(bigInt) === "undefined") |
|||
alert("You need to have included BigInteger.js for eth to work.") |
|||
|
|||
String.prototype.pad = function(l, r) { |
|||
if (r === null) { |
|||
r = l |
|||
if (!(this.substr(0, 2) == "0x" || /^\d+$/.test(this))) |
|||
l = 0 |
|||
} |
|||
var ret = this.bin(); |
|||
while (ret.length < l) |
|||
ret = "\0" + ret |
|||
while (ret.length < r) |
|||
ret = ret + "\0" |
|||
return ret; |
|||
} |
|||
|
|||
String.prototype.unpad = function() { |
|||
var i = this.length; |
|||
while (i && this[i - 1] == "\0") |
|||
--i |
|||
return this.substr(0, i) |
|||
} |
|||
|
|||
String.prototype.bin = function() { |
|||
if (this.substr(0, 2) == "0x") { |
|||
bytes = [] |
|||
var i = 2; |
|||
// Check if it's odd - pad with a zero if so.
|
|||
if (this.length % 2) |
|||
bytes.push(parseInt(this.substr(i++, 1), 16)) |
|||
for (; i < this.length - 1; i += 2) |
|||
bytes.push(parseInt(this.substr(i, 2), 16)); |
|||
return String.fromCharCode.apply(String, bytes); |
|||
} else if (/^\d+$/.test(this)) |
|||
return bigInt(this.substr(0)).toHex().bin() |
|||
|
|||
// Otherwise we'll return the "String" object instead of an actual string
|
|||
return this.substr(0, this.length) |
|||
} |
|||
|
|||
String.prototype.unbin = function() { |
|||
var i, l, o = ''; |
|||
for(i = 0, l = this.length; i < l; i++) { |
|||
var n = this.charCodeAt(i).toString(16); |
|||
o += n.length < 2 ? '0' + n : n; |
|||
} |
|||
|
|||
return "0x" + o; |
|||
} |
|||
|
|||
String.prototype.dec = function() { |
|||
return bigInt(this.substr(0)).toString() |
|||
} |
|||
|
|||
String.prototype.hex = function() { |
|||
return bigInt(this.substr(0)).toHex() |
|||
} |
|||
|
|||
|
@ -0,0 +1,24 @@ |
|||
[ |
|||
{ "method": "procedures", "params": null, "order": [], "returns": [] }, |
|||
{ "method": "coinbase", "params": null, "order": [], "returns" : "" }, |
|||
{ "method": "isListening", "params": null, "order": [], "returns" : false }, |
|||
{ "method": "isMining", "params": null, "order": [], "returns" : false }, |
|||
{ "method": "gasPrice", "params": null, "order": [], "returns" : "" }, |
|||
{ "method": "key", "params": null, "order": [], "returns" : "" }, |
|||
{ "method": "keys", "params": null, "order": [], "returns" : [] }, |
|||
{ "method": "peerCount", "params": null, "order": [], "returns" : 0 }, |
|||
{ "method": "balanceAt", "params": { "a": "" }, "order": ["a"], "returns" : "" }, |
|||
{ "method": "storageAt", "params": { "a": "", "x": "" }, "order": ["a", "x"], "returns" : "" }, |
|||
{ "method": "txCountAt", "params": { "a": "" },"order": ["a"], "returns" : "" }, |
|||
{ "method": "isContractAt", "params": { "a": "" }, "order": ["a"], "returns" : false }, |
|||
{ "method": "create", "params": { "sec": "", "xEndowment": "", "bCode": "", "xGas": "", "xGasPrice": "" }, "order": ["sec", "xEndowment", "bCode", "xGas", "xGasPrice"] , "returns": "" }, |
|||
{ "method": "transact", "params": { "sec": "", "xValue": "", "aDest": "", "bData": "", "xGas": "", "xGasPrice": "" }, "order": ["sec", "xValue", "aDest", "bData", "xGas", "xGasPrice"], "returns": {} }, |
|||
{ "method": "secretToAddress", "params": { "a": "" }, "order": ["a"], "returns" : "" }, |
|||
{ "method": "lll", "params": { "s": "" }, "order": ["s"], "returns" : "" } |
|||
, |
|||
{ "method": "check", "params": { "a": [] }, "order": ["a"], "returns" : [] }, |
|||
{ "method": "lastBlock", "params": null, "order": [], "returns": {}}, |
|||
{ "method": "block", "params": {"a":""}, "order": ["a"], "returns": {}} |
|||
] |
|||
|
|||
|
@ -0,0 +1,40 @@ |
|||
cmake_policy(SET CMP0015 NEW) |
|||
|
|||
aux_source_directory(. SRC_LIST) |
|||
|
|||
include_directories(..) |
|||
|
|||
set(EXECUTABLE exp) |
|||
|
|||
add_executable(${EXECUTABLE} ${SRC_LIST}) |
|||
|
|||
target_link_libraries(${EXECUTABLE} ethereum) |
|||
target_link_libraries(${EXECUTABLE} gmp) |
|||
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS}) |
|||
if(MINIUPNPC_LS) |
|||
target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS}) |
|||
endif() |
|||
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) |
|||
|
|||
if ("${TARGET_PLATFORM}" STREQUAL "w64") |
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") |
|||
target_link_libraries(${EXECUTABLE} gcc) |
|||
target_link_libraries(${EXECUTABLE} gdi32) |
|||
target_link_libraries(${EXECUTABLE} ws2_32) |
|||
target_link_libraries(${EXECUTABLE} mswsock) |
|||
target_link_libraries(${EXECUTABLE} shlwapi) |
|||
target_link_libraries(${EXECUTABLE} iphlpapi) |
|||
target_link_libraries(${EXECUTABLE} boost_system-mt-s) |
|||
target_link_libraries(${EXECUTABLE} boost_filesystem-mt-s) |
|||
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) |
|||
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) |
|||
elseif (UNIX) |
|||
else () |
|||
target_link_libraries(${EXECUTABLE} boost_system) |
|||
target_link_libraries(${EXECUTABLE} boost_filesystem) |
|||
find_package(Threads REQUIRED) |
|||
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) |
|||
endif () |
|||
|
|||
install( TARGETS ${EXECUTABLE} DESTINATION bin ) |
|||
|
@ -0,0 +1,44 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file main.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
* Ethereum client. |
|||
*/ |
|||
|
|||
#include <libethential/Log.h> |
|||
#include <libethential/Common.h> |
|||
#include <libethential/CommonData.h> |
|||
#include "BuildInfo.h" |
|||
using namespace std; |
|||
using namespace eth; |
|||
|
|||
int main(int, char**) |
|||
{ |
|||
u256 z = 0; |
|||
u256 s = 7; |
|||
u256 ms = z - s; |
|||
s256 ams = -7; |
|||
s256 sms = u2s(ms); |
|||
cnote << sms; |
|||
cnote << ams; |
|||
cnote << ms; |
|||
u256 t = 3; |
|||
s256 st = u2s(t); |
|||
cnote << ms << t << (sms % t) << sms << st << (s2u(sms % st) + 70); |
|||
return 0; |
|||
} |
@ -0,0 +1,19 @@ |
|||
{ |
|||
(def 'gav 0x51ba59315b3a95761d0863b05ccc7a7f54703d99) |
|||
|
|||
(def 'alloc (len) (asm msize 0 1 len msize add sub mstore8)) |
|||
|
|||
(def 'send (to value) (call (- (gas) 21) to value 0 0 0 0)) |
|||
(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0)) |
|||
(def 'msg (gaslimit to value data datasize outsize) { [32]:outsize [0]:(alloc @32) (call gaslimit to value data datasize @0 @32) @0 }) |
|||
(def 'msg (gaslimit to value data datasize) { (call gaslimit to value data datasize 0 32) @0 }) |
|||
(def 'msg (gaslimit to value data) { [0]:data (msg gaslimit to value 0 32) }) |
|||
(def 'create (to value code) { [0]:(msize) (create to value @0 (lll code @0)) }) |
|||
|
|||
(def 'sha3 (val) { [0]:val (sha3 0 32) }) |
|||
(def 'return (val) { [0]:val (return 0 32) }) |
|||
|
|||
(def 'makeperm (name pos) { (def name (sload pos)) (def name (v) (sstore pos v)) } ) |
|||
(def 'permcount 0) |
|||
(def 'perm (name) { (makeperm name permcount) (def 'permcount (+ permcount 1)) } ) |
|||
} |
@ -0,0 +1,12 @@ |
|||
#pragma once |
|||
|
|||
#include "BlockInfo.h" |
|||
#include "CommonEth.h" |
|||
#include "Dagger.h" |
|||
#include "FileSystem.h" |
|||
#include "MemoryDB.h" |
|||
#include "OverlayDB.h" |
|||
#include "SHA3.h" |
|||
#include "TrieCommon.h" |
|||
#include "TrieDB.h" |
|||
#include "UPnP.h" |
@ -0,0 +1,122 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file BlockInfo.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <libethential/Common.h> |
|||
#include <libethential/RLP.h> |
|||
#include "CommonEth.h" |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
extern u256 c_genesisDifficulty; |
|||
|
|||
/** @brief Encapsulation of a block header.
|
|||
* Class to contain all of a block header's data. It is able to parse a block header and populate |
|||
* from some given RLP block serialisation with the static fromHeader(), through the method |
|||
* populateFromHeader(). This will conduct a minimal level of verification. In this case extra |
|||
* verification can be performed through verifyInternals() and verifyParent(). |
|||
* |
|||
* The object may also be populated from an entire block through the explicit |
|||
* constructor BlockInfo(bytesConstRef) and manually with the populate() method. These will |
|||
* conduct verification of the header against the other information in the block. |
|||
* |
|||
* The object may be populated with a template given a parent BlockInfo object with the |
|||
* populateFromParent() method. The genesis block info may be retrieved with genesis() and the |
|||
* corresponding RLP block created with createGenesisBlock(). |
|||
* |
|||
* The difficulty and gas-limit derivations may be calculated with the calculateDifficulty() |
|||
* and calculateGasLimit() and the object serialised to RLP with fillStream. To determine the |
|||
* header hash without the nonce (for mining), the method headerHashWithoutNonce() is provided. |
|||
* |
|||
* The defualt constructor creates an empty object, which can be tested against with the boolean |
|||
* conversion operator. |
|||
*/ |
|||
struct BlockInfo |
|||
{ |
|||
public: |
|||
h256 hash; ///< SHA3 hash of the entire block! Not serialised (the only member not contained in a block header).
|
|||
h256 parentHash; |
|||
h256 sha3Uncles; |
|||
Address coinbaseAddress; |
|||
h256 stateRoot; |
|||
h256 transactionsRoot; |
|||
u256 difficulty; |
|||
u256 number; |
|||
u256 minGasPrice; |
|||
u256 gasLimit; |
|||
u256 gasUsed; |
|||
u256 timestamp; |
|||
bytes extraData; |
|||
h256 nonce; |
|||
|
|||
BlockInfo(); |
|||
explicit BlockInfo(bytes const& _block): BlockInfo(&_block) {} |
|||
explicit BlockInfo(bytesConstRef _block); |
|||
|
|||
static BlockInfo fromHeader(bytesConstRef _block); |
|||
|
|||
explicit operator bool() const { return timestamp != Invalid256; } |
|||
|
|||
bool operator==(BlockInfo const& _cmp) const |
|||
{ |
|||
return parentHash == _cmp.parentHash && |
|||
sha3Uncles == _cmp.sha3Uncles && |
|||
coinbaseAddress == _cmp.coinbaseAddress && |
|||
stateRoot == _cmp.stateRoot && |
|||
transactionsRoot == _cmp.transactionsRoot && |
|||
difficulty == _cmp.difficulty && |
|||
number == _cmp.number && |
|||
minGasPrice == _cmp.minGasPrice && |
|||
gasLimit == _cmp.gasLimit && |
|||
gasUsed == _cmp.gasUsed && |
|||
timestamp == _cmp.timestamp && |
|||
extraData == _cmp.extraData && |
|||
nonce == _cmp.nonce; |
|||
} |
|||
bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } |
|||
|
|||
void populateFromHeader(RLP const& _header, bool _checkNonce = true); |
|||
void populate(bytesConstRef _block, bool _checkNonce = true); |
|||
void populate(bytes const& _block, bool _checkNonce = true) { populate(&_block, _checkNonce); } |
|||
void verifyInternals(bytesConstRef _block) const; |
|||
void verifyParent(BlockInfo const& _parent) const; |
|||
void populateFromParent(BlockInfo const& parent); |
|||
|
|||
u256 calculateDifficulty(BlockInfo const& _parent) const; |
|||
u256 calculateGasLimit(BlockInfo const& _parent) const; |
|||
|
|||
/// No-nonce sha3 of the header only.
|
|||
h256 headerHashWithoutNonce() const; |
|||
void fillStream(RLPStream& _s, bool _nonce) const; |
|||
}; |
|||
|
|||
inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) |
|||
{ |
|||
_out << _bi.hash << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.transactionsRoot << " " << |
|||
_bi.difficulty << " " << _bi.number << " " << _bi.minGasPrice << " " << _bi.gasLimit << " " << _bi.gasUsed << " " << _bi.timestamp << " " << _bi.nonce; |
|||
return _out; |
|||
} |
|||
|
|||
} |
|||
|
|||
|
@ -0,0 +1,61 @@ |
|||
cmake_policy(SET CMP0015 NEW) |
|||
|
|||
aux_source_directory(. SRC_LIST) |
|||
|
|||
set(EXECUTABLE ethcore) |
|||
|
|||
# set(CMAKE_INSTALL_PREFIX ../lib) |
|||
if(ETH_STATIC) |
|||
add_library(${EXECUTABLE} STATIC ${SRC_LIST}) |
|||
else() |
|||
add_library(${EXECUTABLE} SHARED ${SRC_LIST}) |
|||
endif() |
|||
|
|||
file(GLOB HEADERS "*.h") |
|||
|
|||
include_directories(..) |
|||
|
|||
target_link_libraries(${EXECUTABLE} ethential) |
|||
target_link_libraries(${EXECUTABLE} secp256k1) |
|||
target_link_libraries(${EXECUTABLE} gmp) |
|||
if(MINIUPNPC_LS) |
|||
target_link_libraries(${EXECUTABLE} ${MINIUPNPC_LS}) |
|||
endif() |
|||
target_link_libraries(${EXECUTABLE} ${LEVELDB_LS}) |
|||
target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LS}) |
|||
|
|||
if("${TARGET_PLATFORM}" STREQUAL "w64") |
|||
target_link_libraries(${EXECUTABLE} boost_system-mt-s) |
|||
target_link_libraries(${EXECUTABLE} boost_filesystem-mt-s) |
|||
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) |
|||
target_link_libraries(${EXECUTABLE} iphlpapi) |
|||
target_link_libraries(${EXECUTABLE} ws2_32) |
|||
target_link_libraries(${EXECUTABLE} mswsock) |
|||
target_link_libraries(${EXECUTABLE} shlwapi) |
|||
elseif (APPLE) |
|||
# Latest mavericks boost libraries only come with -mt |
|||
target_link_libraries(${EXECUTABLE} boost_system-mt) |
|||
target_link_libraries(${EXECUTABLE} boost_filesystem-mt) |
|||
target_link_libraries(${EXECUTABLE} boost_thread-mt) |
|||
find_package(Threads REQUIRED) |
|||
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) |
|||
elseif (UNIX) |
|||
find_package(Boost 1.53 REQUIRED COMPONENTS filesystem) |
|||
target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARY}) |
|||
target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARY}) |
|||
target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY}) |
|||
target_link_libraries(${EXECUTABLE} ${Boost_DATE_TIME_LIBRARY}) |
|||
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) |
|||
else () |
|||
target_link_libraries(${EXECUTABLE} boost_system) |
|||
target_link_libraries(${EXECUTABLE} boost_filesystem) |
|||
target_link_libraries(${EXECUTABLE} boost_thread) |
|||
find_package(Threads REQUIRED) |
|||
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) |
|||
endif () |
|||
|
|||
message("Installation path: ${CMAKE_INSTALL_PREFIX}") |
|||
|
|||
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) |
|||
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) |
|||
|
@ -1,56 +1,40 @@ |
|||
#pragma once |
|||
|
|||
#include <exception> |
|||
#include "CommonIO.h" |
|||
#include "CommonData.h" |
|||
#include "FixedHash.h" |
|||
#include <libethential/Exceptions.h> |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
class Exception: public std::exception |
|||
{ |
|||
public: |
|||
virtual std::string description() const { return typeid(*this).name(); } |
|||
virtual char const* what() const noexcept { return typeid(*this).name(); } |
|||
}; |
|||
|
|||
class BadHexCharacter: public Exception {}; |
|||
class NotEnoughCash: public Exception {}; |
|||
|
|||
class RLPException: public Exception {}; |
|||
class BadCast: public RLPException {}; |
|||
class BadRLP: public RLPException {}; |
|||
|
|||
class VMException: public Exception {}; |
|||
class StepsDone: public VMException {}; |
|||
class BreakPointHit: public VMException {}; |
|||
class BadInstruction: public VMException {}; |
|||
class OutOfGas: public VMException {}; |
|||
class StackTooSmall: public VMException { public: StackTooSmall(u256 _req, u256 _got): req(_req), got(_got) {} u256 req; u256 got; }; |
|||
class OperandOutOfRange: public VMException { public: OperandOutOfRange(u256 _min, u256 _max, u256 _got): mn(_min), mx(_max), got(_got) {} u256 mn; u256 mx; u256 got; }; |
|||
|
|||
class GasPriceTooLow: public Exception {}; |
|||
class BlockGasLimitReached: public Exception {}; |
|||
class NoSuchContract: public Exception {}; |
|||
class ContractAddressCollision: public Exception {}; |
|||
class FeeTooSmall: public Exception {}; |
|||
class TooMuchGasUsed: public Exception {}; |
|||
class ExtraDataTooBig: public Exception {}; |
|||
class InvalidSignature: public Exception {}; |
|||
class InvalidTransactionFormat: public Exception { public: InvalidTransactionFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid transaction format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } }; |
|||
class InvalidBlockFormat: public Exception { public: InvalidBlockFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } }; |
|||
class InvalidBlockHeaderFormat: public Exception { public: InvalidBlockHeaderFormat(int _f, bytesConstRef _d): m_f(_f), m_d(_d.toBytes()) {} int m_f; bytes m_d; virtual std::string description() const { return "Invalid block header format: Bad field " + toString(m_f) + " (" + toHex(m_d) + ")"; } }; |
|||
class InvalidUnclesHash: public Exception {}; |
|||
class InvalidUncle: public Exception {}; |
|||
class UncleNotAnUncle: public Exception {}; |
|||
class DuplicateUncleNonce: public Exception {}; |
|||
class InvalidStateRoot: public Exception {}; |
|||
class InvalidTransactionsHash: public Exception { public: InvalidTransactionsHash(h256 _head, h256 _real): m_head(_head), m_real(_real) {} h256 m_head; h256 m_real; virtual std::string description() const { return "Invalid transactions hash: header says: " + toHex(m_head.ref()) + " block is:" + toHex(m_real.ref()); } }; |
|||
class InvalidTransaction: public Exception {}; |
|||
class InvalidDifficulty: public Exception {}; |
|||
class InvalidGasLimit: public Exception {}; |
|||
class InvalidMinGasPrice: public Exception { public: InvalidMinGasPrice(u256 _provided = 0, u256 _limit = 0): provided(_provided), limit(_limit) {} u256 provided; u256 limit; virtual std::string description() const { return "Invalid minimum gas price (provided: " + toString(provided) + " limit:" + toString(limit) + ")"; } }; |
|||
class InvalidTransactionGasUsed: public Exception {}; |
|||
class InvalidTransactionStateRoot: public Exception {}; |
|||
class InvalidTimestamp: public Exception {}; |
|||
class InvalidNonce: public Exception { public: InvalidNonce(u256 _required = 0, u256 _candidate = 0): required(_required), candidate(_candidate) {} u256 required; u256 candidate; virtual std::string description() const { return "Invalid nonce (r: " + toString(required) + " c:" + toString(candidate) + ")"; } }; |
|||
class InvalidBlockNonce: public Exception { public: InvalidBlockNonce(h256 _h = h256(), h256 _n = h256(), u256 _d = 0): h(_h), n(_n), d(_d) {} h256 h; h256 n; u256 d; virtual std::string description() const { return "Invalid nonce (h: " + toString(h) + " n:" + toString(n) + " d:" + toString(d) + ")"; } }; |
|||
class InvalidParentHash: public Exception {}; |
|||
class InvalidNumber: public Exception {}; |
|||
class InvalidContractAddress: public Exception {}; |
|||
class NoNetworking: public Exception {}; |
|||
class NoUPnPDevice: public Exception {}; |
|||
class RootNotFound: public Exception {}; |
|||
|
|||
} |
@ -0,0 +1,115 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file MemoryDB.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include <libethential/Common.h> |
|||
#include "MemoryDB.h" |
|||
using namespace std; |
|||
using namespace eth; |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
std::map<h256, std::string> MemoryDB::get() const |
|||
{ |
|||
if (!m_enforceRefs) |
|||
return m_over; |
|||
std::map<h256, std::string> ret; |
|||
for (auto const& i: m_refCount) |
|||
if (i.second) |
|||
ret.insert(*m_over.find(i.first)); |
|||
return ret; |
|||
} |
|||
|
|||
std::string MemoryDB::lookup(h256 _h) const |
|||
{ |
|||
auto it = m_over.find(_h); |
|||
if (it != m_over.end()) |
|||
{ |
|||
if (!m_enforceRefs || (m_refCount.count(it->first) && m_refCount.at(it->first))) |
|||
return it->second; |
|||
// else if (m_enforceRefs && m_refCount.count(it->first) && !m_refCount.at(it->first))
|
|||
// cnote << "Lookup required for value with no refs. Let's hope it's in the DB." << _h.abridged();
|
|||
} |
|||
return std::string(); |
|||
} |
|||
|
|||
bool MemoryDB::exists(h256 _h) const |
|||
{ |
|||
auto it = m_over.find(_h); |
|||
if (it != m_over.end() && (!m_enforceRefs || (m_refCount.count(it->first) && m_refCount.at(it->first)))) |
|||
return true; |
|||
return false; |
|||
} |
|||
|
|||
void MemoryDB::insert(h256 _h, bytesConstRef _v) |
|||
{ |
|||
m_over[_h] = _v.toString(); |
|||
m_refCount[_h]++; |
|||
#if ETH_PARANOIA |
|||
dbdebug << "INST" << _h.abridged() << "=>" << m_refCount[_h]; |
|||
#endif |
|||
} |
|||
|
|||
bool MemoryDB::kill(h256 _h) |
|||
{ |
|||
if (m_refCount.count(_h)) |
|||
{ |
|||
if (m_refCount[_h] > 0) |
|||
--m_refCount[_h]; |
|||
#if ETH_PARANOIA |
|||
else |
|||
{ |
|||
// If we get to this point, then there was probably a node in the level DB which we need to remove and which we have previously
|
|||
// used as part of the memory-based MemoryDB. Nothing to be worried about *as long as the node exists in the DB*.
|
|||
dbdebug << "NOKILL-WAS" << _h.abridged(); |
|||
return false; |
|||
} |
|||
dbdebug << "KILL" << _h.abridged() << "=>" << m_refCount[_h]; |
|||
return true; |
|||
} |
|||
else |
|||
{ |
|||
dbdebug << "NOKILL" << _h.abridged(); |
|||
return false; |
|||
} |
|||
#else |
|||
} |
|||
return true; |
|||
#endif |
|||
} |
|||
|
|||
void MemoryDB::purge() |
|||
{ |
|||
for (auto const& i: m_refCount) |
|||
if (!i.second) |
|||
m_over.erase(i.first); |
|||
} |
|||
|
|||
set<h256> MemoryDB::keys() const |
|||
{ |
|||
set<h256> ret; |
|||
for (auto const& i: m_refCount) |
|||
if (i.second) |
|||
ret.insert(i.first); |
|||
return ret; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,85 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file MemoryDB.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <map> |
|||
#include <libethential/Common.h> |
|||
#include <libethential/FixedHash.h> |
|||
#include <libethential/Log.h> |
|||
#include <libethential/RLP.h> |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
struct DBChannel: public LogChannel { static const char* name() { return "TDB"; } static const int verbosity = 12; }; |
|||
|
|||
#define dbdebug clog(DBChannel) |
|||
|
|||
class MemoryDB |
|||
{ |
|||
friend class EnforceRefs; |
|||
|
|||
public: |
|||
MemoryDB() {} |
|||
|
|||
void clear() { m_over.clear(); } |
|||
std::map<h256, std::string> get() const; |
|||
|
|||
std::string lookup(h256 _h) const; |
|||
bool exists(h256 _h) const; |
|||
void insert(h256 _h, bytesConstRef _v); |
|||
bool kill(h256 _h); |
|||
void purge(); |
|||
|
|||
std::set<h256> keys() const; |
|||
|
|||
protected: |
|||
std::map<h256, std::string> m_over; |
|||
std::map<h256, uint> m_refCount; |
|||
|
|||
mutable bool m_enforceRefs = false; |
|||
}; |
|||
|
|||
class EnforceRefs |
|||
{ |
|||
public: |
|||
EnforceRefs(MemoryDB const& _o, bool _r): m_o(_o), m_r(_o.m_enforceRefs) { _o.m_enforceRefs = _r; } |
|||
~EnforceRefs() { m_o.m_enforceRefs = m_r; } |
|||
|
|||
private: |
|||
MemoryDB const& m_o; |
|||
bool m_r; |
|||
}; |
|||
|
|||
inline std::ostream& operator<<(std::ostream& _out, MemoryDB const& _m) |
|||
{ |
|||
for (auto i: _m.get()) |
|||
{ |
|||
_out << i.first << ": "; |
|||
_out << RLP(i.second); |
|||
_out << " " << toHex(i.second); |
|||
_out << std::endl; |
|||
} |
|||
return _out; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,99 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file TrieDB.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include <libethential/Common.h> |
|||
#include "OverlayDB.h" |
|||
using namespace std; |
|||
using namespace eth; |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
OverlayDB::~OverlayDB() |
|||
{ |
|||
if (m_db.use_count() == 1 && m_db.get()) |
|||
cnote << "Closing state DB"; |
|||
} |
|||
|
|||
void OverlayDB::setDB(ldb::DB* _db, bool _clearOverlay) |
|||
{ |
|||
m_db = std::shared_ptr<ldb::DB>(_db); |
|||
if (_clearOverlay) |
|||
m_over.clear(); |
|||
} |
|||
|
|||
void OverlayDB::commit() |
|||
{ |
|||
if (m_db) |
|||
{ |
|||
// cnote << "Committing nodes to disk DB:";
|
|||
for (auto const& i: m_over) |
|||
{ |
|||
// cnote << i.first << "#" << m_refCount[i.first];
|
|||
if (m_refCount[i.first]) |
|||
m_db->Put(m_writeOptions, ldb::Slice((char const*)i.first.data(), i.first.size), ldb::Slice(i.second.data(), i.second.size())); |
|||
} |
|||
m_over.clear(); |
|||
m_refCount.clear(); |
|||
} |
|||
} |
|||
|
|||
void OverlayDB::rollback() |
|||
{ |
|||
m_over.clear(); |
|||
m_refCount.clear(); |
|||
} |
|||
|
|||
std::string OverlayDB::lookup(h256 _h) const |
|||
{ |
|||
std::string ret = MemoryDB::lookup(_h); |
|||
if (ret.empty() && m_db) |
|||
m_db->Get(m_readOptions, ldb::Slice((char const*)_h.data(), 32), &ret); |
|||
return ret; |
|||
} |
|||
|
|||
bool OverlayDB::exists(h256 _h) const |
|||
{ |
|||
if (MemoryDB::exists(_h)) |
|||
return true; |
|||
std::string ret; |
|||
if (m_db) |
|||
m_db->Get(m_readOptions, ldb::Slice((char const*)_h.data(), 32), &ret); |
|||
return !ret.empty(); |
|||
} |
|||
|
|||
void OverlayDB::kill(h256 _h) |
|||
{ |
|||
#if ETH_PARANOIA |
|||
if (!MemoryDB::kill(_h)) |
|||
{ |
|||
std::string ret; |
|||
if (m_db) |
|||
m_db->Get(m_readOptions, ldb::Slice((char const*)_h.data(), 32), &ret); |
|||
if (ret.empty()) |
|||
cnote << "Decreasing DB node ref count below zero with no DB node. Probably have a corrupt Trie." << _h.abridged(); |
|||
} |
|||
#else |
|||
MemoryDB::kill(_h); |
|||
#endif |
|||
} |
|||
|
|||
} |
@ -0,0 +1,58 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file MemoryDB.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include <libethential/Common.h> |
|||
#include <libethential/Log.h> |
|||
#include "MemoryDB.h" |
|||
namespace ldb = leveldb; |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
class OverlayDB: public MemoryDB |
|||
{ |
|||
public: |
|||
OverlayDB(ldb::DB* _db = nullptr): m_db(_db) {} |
|||
~OverlayDB(); |
|||
|
|||
ldb::DB* db() const { return m_db.get(); } |
|||
void setDB(ldb::DB* _db, bool _clearOverlay = true); |
|||
|
|||
void commit(); |
|||
void rollback(); |
|||
|
|||
std::string lookup(h256 _h) const; |
|||
bool exists(h256 _h) const; |
|||
void kill(h256 _h); |
|||
|
|||
private: |
|||
using MemoryDB::clear; |
|||
|
|||
std::shared_ptr<ldb::DB> m_db; |
|||
|
|||
ldb::ReadOptions m_readOptions; |
|||
ldb::WriteOptions m_writeOptions; |
|||
}; |
|||
|
|||
} |
@ -0,0 +1,68 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file SHA3.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "SHA3.h" |
|||
#include "CryptoHeaders.h" |
|||
|
|||
using namespace std; |
|||
using namespace eth; |
|||
|
|||
h256 eth::EmptySHA3 = sha3(bytesConstRef()); |
|||
|
|||
std::string eth::sha3(std::string const& _input, bool _hex) |
|||
{ |
|||
if (!_hex) |
|||
{ |
|||
string ret(32, '\0'); |
|||
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)ret.data(), 32)); |
|||
return ret; |
|||
} |
|||
|
|||
uint8_t buf[32]; |
|||
sha3(bytesConstRef((byte const*)_input.data(), _input.size()), bytesRef((byte*)&(buf[0]), 32)); |
|||
std::string ret(64, '\0'); |
|||
for (unsigned int i = 0; i < 32; i++) |
|||
sprintf((char*)(ret.data())+i*2, "%02x", buf[i]); |
|||
return ret; |
|||
} |
|||
|
|||
void eth::sha3(bytesConstRef _input, bytesRef _output) |
|||
{ |
|||
CryptoPP::SHA3_256 ctx; |
|||
ctx.Update((byte*)_input.data(), _input.size()); |
|||
assert(_output.size() >= 32); |
|||
ctx.Final(_output.data()); |
|||
} |
|||
|
|||
bytes eth::sha3Bytes(bytesConstRef _input) |
|||
{ |
|||
bytes ret(32); |
|||
sha3(_input, &ret); |
|||
return ret; |
|||
} |
|||
|
|||
h256 eth::sha3(bytesConstRef _input) |
|||
{ |
|||
h256 ret; |
|||
sha3(_input, bytesRef(&ret[0], 32)); |
|||
return ret; |
|||
} |
|||
|
@ -0,0 +1,61 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file FixedHash.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
* |
|||
* The FixedHash fixed-size "hash" container type. |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <string> |
|||
#include <libethential/FixedHash.h> |
|||
#include <libethential/vector_ref.h> |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
// SHA-3 convenience routines.
|
|||
|
|||
/// Calculate SHA3-256 hash of the given input and load it into the given output.
|
|||
void sha3(bytesConstRef _input, bytesRef _output); |
|||
|
|||
/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data.
|
|||
std::string sha3(std::string const& _input, bool _isNibbles); |
|||
|
|||
/// Calculate SHA3-256 hash of the given input, returning as a byte array.
|
|||
bytes sha3Bytes(bytesConstRef _input); |
|||
|
|||
/// Calculate SHA3-256 hash of the given input (presented as a binary string), returning as a byte array.
|
|||
inline bytes sha3Bytes(std::string const& _input) { return sha3Bytes((std::string*)&_input); } |
|||
|
|||
/// Calculate SHA3-256 hash of the given input, returning as a byte array.
|
|||
inline bytes sha3Bytes(bytes const& _input) { return sha3Bytes((bytes*)&_input); } |
|||
|
|||
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
|
|||
h256 sha3(bytesConstRef _input); |
|||
|
|||
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
|
|||
inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_input)); } |
|||
|
|||
/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash.
|
|||
inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } |
|||
|
|||
extern h256 EmptySHA3; |
|||
|
|||
} |
@ -0,0 +1,8 @@ |
|||
#pragma once |
|||
|
|||
#include "Common.h" |
|||
#include "CommonData.h" |
|||
#include "CommonIO.h" |
|||
#include "FixedHash.h" |
|||
#include "Log.h" |
|||
#include "RLP.h" |
@ -0,0 +1,53 @@ |
|||
cmake_policy(SET CMP0015 NEW) |
|||
|
|||
if (CMAKE_MAJOR_VERSION GREATER 1 AND CMAKE_MINOR_VERSION GREATER 7 AND CMAKE_PATCH_VERSION GREATER 11) |
|||
cmake_policy(SET CMP0022 NEW) |
|||
endif() |
|||
|
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") |
|||
|
|||
aux_source_directory(. SRC_LIST) |
|||
|
|||
set(EXECUTABLE ethential) |
|||
|
|||
# set(CMAKE_INSTALL_PREFIX ../lib) |
|||
if(ETH_STATIC) |
|||
add_library(${EXECUTABLE} STATIC ${SRC_LIST}) |
|||
else() |
|||
add_library(${EXECUTABLE} SHARED ${SRC_LIST}) |
|||
endif() |
|||
file(GLOB HEADERS "*.h") |
|||
|
|||
include_directories(..) |
|||
|
|||
target_link_libraries(${EXECUTABLE} ethential) |
|||
|
|||
if("${TARGET_PLATFORM}" STREQUAL "w64") |
|||
include_directories(/usr/x86_64-w64-mingw32/include/cryptopp) |
|||
target_link_libraries(${EXECUTABLE} boost_system-mt-s) |
|||
target_link_libraries(${EXECUTABLE} boost_thread_win32-mt-s) |
|||
target_link_libraries(${EXECUTABLE} iphlpapi) |
|||
target_link_libraries(${EXECUTABLE} ws2_32) |
|||
target_link_libraries(${EXECUTABLE} mswsock) |
|||
target_link_libraries(${EXECUTABLE} shlwapi) |
|||
elseif (APPLE) |
|||
# Latest mavericks boost libraries only come with -mt |
|||
target_link_libraries(${EXECUTABLE} boost_system-mt) |
|||
target_link_libraries(${EXECUTABLE} boost_filesystem-mt) |
|||
target_link_libraries(${EXECUTABLE} boost_thread-mt) |
|||
find_package(Threads REQUIRED) |
|||
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) |
|||
elseif (UNIX) |
|||
target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARY}) |
|||
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) |
|||
else () |
|||
target_link_libraries(${EXECUTABLE} boost_thread) |
|||
find_package(Threads REQUIRED) |
|||
target_link_libraries(${EXECUTABLE} ${CMAKE_THREAD_LIBS_INIT}) |
|||
endif () |
|||
|
|||
message("Installation path: ${CMAKE_INSTALL_PREFIX}") |
|||
|
|||
install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) |
|||
install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) |
|||
|
@ -0,0 +1,48 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file Exceptions.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <exception> |
|||
#include "CommonIO.h" |
|||
#include "CommonData.h" |
|||
#include "FixedHash.h" |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
class Exception: public std::exception |
|||
{ |
|||
public: |
|||
virtual std::string description() const { return typeid(*this).name(); } |
|||
virtual char const* what() const noexcept { return typeid(*this).name(); } |
|||
}; |
|||
|
|||
class BadHexCharacter: public Exception {}; |
|||
|
|||
class RLPException: public Exception {}; |
|||
class BadCast: public RLPException {}; |
|||
class BadRLP: public RLPException {}; |
|||
class NoNetworking: public Exception {}; |
|||
class NoUPnPDevice: public Exception {}; |
|||
class RootNotFound: public Exception {}; |
|||
|
|||
} |
@ -0,0 +1,14 @@ |
|||
#pragma once |
|||
|
|||
#include "AddressState.h" |
|||
#include "BlockChain.h" |
|||
#include "Client.h" |
|||
#include "Defaults.h" |
|||
#include "Executive.h" |
|||
#include "ExtVM.h" |
|||
#include "PeerNetwork.h" |
|||
#include "PeerServer.h" |
|||
#include "PeerSession.h" |
|||
#include "State.h" |
|||
#include "Transaction.h" |
|||
#include "TransactionQueue.h" |
@ -1,94 +0,0 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum 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. |
|||
|
|||
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file BlockInfo.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include "Common.h" |
|||
#include "Transaction.h" |
|||
|
|||
namespace eth |
|||
{ |
|||
|
|||
struct BlockInfo |
|||
{ |
|||
public: |
|||
h256 hash; ///< SHA3 hash of the entire block!
|
|||
h256 parentHash; |
|||
h256 sha3Uncles; |
|||
Address coinbaseAddress; |
|||
h256 stateRoot; |
|||
h256 sha3Transactions; |
|||
u256 difficulty; |
|||
u256 timestamp; |
|||
bytes extraData; |
|||
h256 nonce; |
|||
|
|||
BlockInfo(); |
|||
explicit BlockInfo(bytesConstRef _block); |
|||
|
|||
static BlockInfo fromHeader(bytesConstRef _block); |
|||
|
|||
explicit operator bool() const { return timestamp != Invalid256; } |
|||
|
|||
bool operator==(BlockInfo const& _cmp) const |
|||
{ |
|||
return parentHash == _cmp.parentHash && |
|||
sha3Uncles == _cmp.sha3Uncles && |
|||
coinbaseAddress == _cmp.coinbaseAddress && |
|||
stateRoot == _cmp.stateRoot && |
|||
sha3Transactions == _cmp.sha3Transactions && |
|||
difficulty == _cmp.difficulty && |
|||
timestamp == _cmp.timestamp && |
|||
extraData == _cmp.extraData && |
|||
nonce == _cmp.nonce; |
|||
} |
|||
bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } |
|||
|
|||
static BlockInfo const& genesis() { if (!s_genesis) (s_genesis = new BlockInfo)->populateGenesis(); return *s_genesis; } |
|||
void populateFromHeader(RLP const& _header); |
|||
void populate(bytesConstRef _block); |
|||
void verifyInternals(bytesConstRef _block) const; |
|||
void verifyParent(BlockInfo const& _parent) const; |
|||
|
|||
u256 calculateDifficulty(BlockInfo const& _bi) const; |
|||
|
|||
/// No-nonce sha3 of the header only.
|
|||
h256 headerHashWithoutNonce() const; |
|||
void fillStream(RLPStream& _s, bool _nonce) const; |
|||
|
|||
static bytes createGenesisBlock(); |
|||
|
|||
private: |
|||
void populateGenesis(); |
|||
|
|||
static BlockInfo* s_genesis; |
|||
}; |
|||
|
|||
inline std::ostream& operator<<(std::ostream& _out, BlockInfo const& _bi) |
|||
{ |
|||
_out << _bi.hash << " " << _bi.parentHash << " " << _bi.sha3Uncles << " " << _bi.coinbaseAddress << " " << _bi.stateRoot << " " << _bi.sha3Transactions << " " << |
|||
_bi.difficulty << " " << _bi.timestamp << " " << _bi.nonce; |
|||
return _out; |
|||
} |
|||
|
|||
} |
|||
|
|||
|
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue