mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Merge branch 'bootstrap'
This commit is contained in:
@@ -142,7 +142,7 @@ bool ConnectionPool::peerConnected(Peer::pointer peer, const NewcoinAddress& na)
|
|||||||
|
|
||||||
void ConnectionPool::peerDisconnected(Peer::pointer peer, const ipPort& ipPeer, const NewcoinAddress& naPeer)
|
void ConnectionPool::peerDisconnected(Peer::pointer peer, const ipPort& ipPeer, const NewcoinAddress& naPeer)
|
||||||
{
|
{
|
||||||
std::cerr << "ConnectionPool::peerDisconnected: " << peer->mIpPort.first << " " << peer->mIpPort.second << std::endl;
|
std::cerr << "ConnectionPool::peerDisconnected: " << ipPeer.first << " " << ipPeer.second << std::endl;
|
||||||
|
|
||||||
boost::mutex::scoped_lock sl(mPeerLock);
|
boost::mutex::scoped_lock sl(mPeerLock);
|
||||||
|
|
||||||
|
|||||||
@@ -137,10 +137,49 @@ void NewcoinAddress::setNodePublic(const std::vector<unsigned char>& vPublic)
|
|||||||
SetData(VER_NODE_PUBLIC, vPublic);
|
SetData(VER_NODE_PUBLIC, vPublic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NewcoinAddress::verifyNodePublic(const uint256& hash, const std::vector<unsigned char>& vchSig) const
|
||||||
|
{
|
||||||
|
CKey pubkey = CKey();
|
||||||
|
bool bVerified;
|
||||||
|
|
||||||
|
if (!pubkey.SetPubKey(getNodePublic()))
|
||||||
|
{
|
||||||
|
// Failed to set public key.
|
||||||
|
bVerified = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bVerified = pubkey.Verify(hash, vchSig);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bVerified;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NewcoinAddress::verifyNodePublic(const uint256& hash, const std::string& strSig) const
|
||||||
|
{
|
||||||
|
std::vector<unsigned char> vchSig(strSig.begin(), strSig.end());
|
||||||
|
|
||||||
|
return verifyNodePublic(hash, vchSig);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// NodePrivate
|
// NodePrivate
|
||||||
//
|
//
|
||||||
|
|
||||||
|
const std::vector<unsigned char>& NewcoinAddress::getNodePrivateData() const
|
||||||
|
{
|
||||||
|
switch (nVersion) {
|
||||||
|
case VER_NONE:
|
||||||
|
throw std::runtime_error("unset source");
|
||||||
|
|
||||||
|
case VER_NODE_PRIVATE:
|
||||||
|
return vchData;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw std::runtime_error(str(boost::format("bad source: %d") % int(nVersion)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint256 NewcoinAddress::getNodePrivate() const
|
uint256 NewcoinAddress::getNodePrivate() const
|
||||||
{
|
{
|
||||||
switch (nVersion) {
|
switch (nVersion) {
|
||||||
@@ -183,6 +222,17 @@ void NewcoinAddress::setNodePrivate(uint256 hash256)
|
|||||||
SetData(VER_NODE_PRIVATE, hash256.begin(), 32);
|
SetData(VER_NODE_PRIVATE, hash256.begin(), 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NewcoinAddress::signNodePrivate(const uint256& hash, std::vector<unsigned char>& vchSig) const
|
||||||
|
{
|
||||||
|
CKey privkey = CKey();
|
||||||
|
|
||||||
|
if (!privkey.SetSecret(getNodePrivateData()))
|
||||||
|
throw std::runtime_error("SetSecret failed.");
|
||||||
|
|
||||||
|
if (!privkey.Sign(hash, vchSig))
|
||||||
|
throw std::runtime_error("Signing failed.");
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// AccountID
|
// AccountID
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -50,10 +50,13 @@ public:
|
|||||||
|
|
||||||
bool setNodePublic(const std::string& strPublic);
|
bool setNodePublic(const std::string& strPublic);
|
||||||
void setNodePublic(const std::vector<unsigned char>& vPublic);
|
void setNodePublic(const std::vector<unsigned char>& vPublic);
|
||||||
|
bool verifyNodePublic(const uint256& hash, const std::vector<unsigned char>& vchSig) const;
|
||||||
|
bool verifyNodePublic(const uint256& hash, const std::string& strSig) const;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Node Private
|
// Node Private
|
||||||
//
|
//
|
||||||
|
const std::vector<unsigned char>& getNodePrivateData() const;
|
||||||
uint256 getNodePrivate() const;
|
uint256 getNodePrivate() const;
|
||||||
|
|
||||||
std::string humanNodePrivate() const;
|
std::string humanNodePrivate() const;
|
||||||
@@ -61,6 +64,7 @@ public:
|
|||||||
bool setNodePrivate(const std::string& strPrivate);
|
bool setNodePrivate(const std::string& strPrivate);
|
||||||
void setNodePrivate(const std::vector<unsigned char>& vPrivate);
|
void setNodePrivate(const std::vector<unsigned char>& vPrivate);
|
||||||
void setNodePrivate(uint256 hash256);
|
void setNodePrivate(uint256 hash256);
|
||||||
|
void signNodePrivate(const uint256& hash, std::vector<unsigned char>& vchSig) const;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Accounts IDs
|
// Accounts IDs
|
||||||
|
|||||||
110
src/Peer.cpp
110
src/Peer.cpp
@@ -16,8 +16,12 @@
|
|||||||
#include "SerializedTransaction.h"
|
#include "SerializedTransaction.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
// Node has this long to verify its identity from connection accepted or connection attempt.
|
||||||
|
#define NODE_VERIFY_SECONDS 15
|
||||||
|
|
||||||
Peer::Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx)
|
Peer::Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx)
|
||||||
: mSocketSsl(io_service, ctx)
|
: mSocketSsl(io_service, ctx),
|
||||||
|
mVerifyTimer(io_service)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,6 +55,10 @@ void Peer::handle_write(const boost::system::error_code& error, size_t bytes_tra
|
|||||||
|
|
||||||
void Peer::detach()
|
void Peer::detach()
|
||||||
{
|
{
|
||||||
|
boost::system::error_code ecCancel;
|
||||||
|
|
||||||
|
(void) mVerifyTimer.cancel();
|
||||||
|
|
||||||
mSendQ.clear();
|
mSendQ.clear();
|
||||||
// mSocketSsl.close();
|
// mSocketSsl.close();
|
||||||
|
|
||||||
@@ -60,6 +68,29 @@ void Peer::detach()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Peer::handleVerifyTimer(const boost::system::error_code& ecResult)
|
||||||
|
{
|
||||||
|
if (ecResult == boost::asio::error::operation_aborted)
|
||||||
|
{
|
||||||
|
// Timer canceled because deadline no longer needed.
|
||||||
|
// std::cerr << "Deadline cancelled." << std::endl;
|
||||||
|
|
||||||
|
nothing(); // Aborter is done.
|
||||||
|
}
|
||||||
|
else if (ecResult)
|
||||||
|
{
|
||||||
|
std::cerr << "Peer verify timer error: " << std::endl;
|
||||||
|
|
||||||
|
// Can't do anything sound.
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "Peer failed to verify in time." << std::endl;
|
||||||
|
detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Begin trying to connect. We are not connected till we know and accept peer's public key.
|
// Begin trying to connect. We are not connected till we know and accept peer's public key.
|
||||||
// Only takes IP addresses (not domains).
|
// Only takes IP addresses (not domains).
|
||||||
void Peer::connect(const std::string strIp, int iPort)
|
void Peer::connect(const std::string strIp, int iPort)
|
||||||
@@ -78,10 +109,21 @@ void Peer::connect(const std::string strIp, int iPort)
|
|||||||
if (err || itrEndpoint == boost::asio::ip::tcp::resolver::iterator())
|
if (err || itrEndpoint == boost::asio::ip::tcp::resolver::iterator())
|
||||||
{
|
{
|
||||||
std::cerr << "Peer::connect: Bad IP" << std::endl;
|
std::cerr << "Peer::connect: Bad IP" << std::endl;
|
||||||
// Failed to resolve ip.
|
|
||||||
detach();
|
detach();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
mVerifyTimer.expires_from_now(boost::posix_time::seconds(NODE_VERIFY_SECONDS), err);
|
||||||
|
mVerifyTimer.async_wait(boost::bind(&Peer::handleVerifyTimer, shared_from_this(), boost::asio::placeholders::error));
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
std::cerr << "Peer::connect: Failed to set timer." << std::endl;
|
||||||
|
detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!err)
|
||||||
{
|
{
|
||||||
std::cerr << "Peer::connect: Connectting: " << mIpPort.first << " " << mIpPort.second << std::endl;
|
std::cerr << "Peer::connect: Connectting: " << mIpPort.first << " " << mIpPort.second << std::endl;
|
||||||
|
|
||||||
@@ -99,7 +141,7 @@ void Peer::connect(const std::string strIp, int iPort)
|
|||||||
// We have an ecrypted connection to the peer.
|
// We have an ecrypted connection to the peer.
|
||||||
// Have it say who it is so we know to avoid redundant connections.
|
// Have it say who it is so we know to avoid redundant connections.
|
||||||
// Establish that it really who we are talking to by having it sign a connection detail.
|
// Establish that it really who we are talking to by having it sign a connection detail.
|
||||||
// XXX Also need to establish no man in the middle attack is in progress.
|
// Also need to establish no man in the middle attack is in progress.
|
||||||
void Peer::handleStart(const boost::system::error_code& error)
|
void Peer::handleStart(const boost::system::error_code& error)
|
||||||
{
|
{
|
||||||
if (error)
|
if (error)
|
||||||
@@ -130,9 +172,7 @@ void Peer::handleConnect(const boost::system::error_code& error, boost::asio::ip
|
|||||||
mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none);
|
mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none);
|
||||||
|
|
||||||
mSocketSsl.async_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::client,
|
mSocketSsl.async_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::client,
|
||||||
boost::bind(&Peer::handleStart,
|
boost::bind(&Peer::handleStart, shared_from_this(), boost::asio::placeholders::error));
|
||||||
shared_from_this(),
|
|
||||||
boost::asio::placeholders::error));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,9 +212,7 @@ void Peer::connected(const boost::system::error_code& error)
|
|||||||
mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none);
|
mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none);
|
||||||
|
|
||||||
mSocketSsl.async_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::server,
|
mSocketSsl.async_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::server,
|
||||||
boost::bind(&Peer::handleStart,
|
boost::bind(&Peer::handleStart, shared_from_this(), boost::asio::placeholders::error));
|
||||||
shared_from_this(),
|
|
||||||
boost::asio::placeholders::error));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,14 +483,15 @@ void Peer::recvHello(newcoin::TMHello& packet)
|
|||||||
#endif
|
#endif
|
||||||
bool bDetach = true;
|
bool bDetach = true;
|
||||||
|
|
||||||
if (mNodePublic.isValid())
|
if (!mNodePublic.setNodePublic(packet.nodepublic()))
|
||||||
{
|
|
||||||
std::cerr << "Recv(Hello): Disconnect: Extraneous node public key." << std::endl;
|
|
||||||
}
|
|
||||||
else if (!mNodePublic.setNodePublic(packet.nodepublic()))
|
|
||||||
{
|
{
|
||||||
std::cerr << "Recv(Hello): Disconnect: Bad node public key." << std::endl;
|
std::cerr << "Recv(Hello): Disconnect: Bad node public key." << std::endl;
|
||||||
}
|
}
|
||||||
|
else if (!mNodePublic.verifyNodePublic(mCookieHash, packet.nodeproof()))
|
||||||
|
{
|
||||||
|
// Unable to verify they have private key for claimed public key.
|
||||||
|
std::cerr << "Recv(Hello): Disconnect: Failed to verify session." << std::endl;
|
||||||
|
}
|
||||||
else if (!theApp->getConnectionPool().peerConnected(shared_from_this(), mNodePublic))
|
else if (!theApp->getConnectionPool().peerConnected(shared_from_this(), mNodePublic))
|
||||||
{
|
{
|
||||||
// Already connected, self, or some other reason.
|
// Already connected, self, or some other reason.
|
||||||
@@ -461,8 +500,13 @@ void Peer::recvHello(newcoin::TMHello& packet)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Successful connection.
|
// Successful connection.
|
||||||
// XXX Kill hello timer.
|
|
||||||
|
// Cancel verification timeout.
|
||||||
|
(void) mVerifyTimer.cancel();
|
||||||
|
|
||||||
// XXX Set timer: connection is in grace period to be useful.
|
// XXX Set timer: connection is in grace period to be useful.
|
||||||
|
// XXX Set timer: connection idle (idle may vary depending on connection type.)
|
||||||
|
|
||||||
bDetach = false;
|
bDetach = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -665,36 +709,50 @@ void Peer::recvLedger(newcoin::TMLedgerData& packet)
|
|||||||
punishPeer(PP_UNWANTED_DATA);
|
punishPeer(PP_UNWANTED_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned char> Peer::getSessionCookie()
|
// Get session information we can sign to prevent man in the middle attack.
|
||||||
|
// (both sides get the same information, neither side controls it)
|
||||||
|
void Peer::getSessionCookie(std::string& strDst)
|
||||||
{
|
{
|
||||||
// get session information we can sign
|
|
||||||
// (both sides get the same information, neither side controls it)
|
|
||||||
SSL* ssl = mSocketSsl.native_handle();
|
SSL* ssl = mSocketSsl.native_handle();
|
||||||
if (!ssl) throw std::runtime_error("No underlying connection");
|
if (!ssl) throw std::runtime_error("No underlying connection");
|
||||||
|
|
||||||
// Get both finished messages
|
// Get both finished messages
|
||||||
unsigned char s1[1024], s2[1024];
|
unsigned char s1[1024], s2[1024];
|
||||||
int l1 = SSL_get_finished(ssl, s1, 1024);
|
int l1 = SSL_get_finished(ssl, s1, sizeof(s1));
|
||||||
int l2 = SSL_get_finished(ssl, s2, 1024);
|
int l2 = SSL_get_peer_finished(ssl, s2, sizeof(s2));
|
||||||
if ((l1 < 16) || (l2 < 16)) throw std::runtime_error("Connection setup not complete");
|
|
||||||
|
if ((l1 < 12) || (l2 < 12))
|
||||||
|
throw std::runtime_error(str(boost::format("Connection setup not complete: %d %d") % l1 % l2));
|
||||||
|
|
||||||
// Hash them and XOR the results
|
// Hash them and XOR the results
|
||||||
unsigned char sha1[32], sha2[32];
|
unsigned char sha1[64], sha2[64];
|
||||||
|
|
||||||
SHA512(s1, l1, sha1);
|
SHA512(s1, l1, sha1);
|
||||||
SHA512(s2, l2, sha2);
|
SHA512(s2, l2, sha2);
|
||||||
for(int i=0; i<32; i++) sha1[i]^=sha2[i];
|
|
||||||
return std::vector<unsigned char>(sha1, sha1+33);
|
for (int i=0; i<sizeof(sha1); i++)
|
||||||
|
sha1[i] ^= sha2[i];
|
||||||
|
|
||||||
|
strDst.assign((char *) &sha1[0], sizeof(sha1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Peer::sendHello()
|
void Peer::sendHello()
|
||||||
{
|
{
|
||||||
// XXX Start timer for hello required by.
|
std::string strCookie;
|
||||||
|
std::vector<unsigned char> vchSig;
|
||||||
|
|
||||||
|
getSessionCookie(strCookie);
|
||||||
|
mCookieHash = Serializer::getSHA512Half(strCookie);
|
||||||
|
|
||||||
|
theApp->getWallet().getNodePrivate().signNodePrivate(mCookieHash, vchSig);
|
||||||
|
|
||||||
newcoin::TMHello* h=new newcoin::TMHello();
|
newcoin::TMHello* h=new newcoin::TMHello();
|
||||||
// set up parameters
|
|
||||||
h->set_version(theConfig.VERSION);
|
h->set_version(theConfig.VERSION);
|
||||||
h->set_ledgerindex(theApp->getOPs().getCurrentLedgerID());
|
h->set_ledgerindex(theApp->getOPs().getCurrentLedgerID());
|
||||||
h->set_nettime(theApp->getOPs().getNetworkTime());
|
h->set_nettime(theApp->getOPs().getNetworkTime());
|
||||||
h->set_nodepublic(theApp->getWallet().getNodePublic().humanNodePublic());
|
h->set_nodepublic(theApp->getWallet().getNodePublic().humanNodePublic());
|
||||||
|
h->set_nodeproof(&vchSig[0], vchSig.size());
|
||||||
h->set_ipv4port(theConfig.PEER_PORT);
|
h->set_ipv4port(theConfig.PEER_PORT);
|
||||||
|
|
||||||
Ledger::pointer closingLedger=theApp->getMasterLedger().getClosingLedger();
|
Ledger::pointer closingLedger=theApp->getMasterLedger().getClosingLedger();
|
||||||
|
|||||||
14
src/Peer.h
14
src/Peer.h
@@ -28,15 +28,19 @@ public:
|
|||||||
static const int psbGotHello=0, psbSentHello=1, psbInMap=2, psbTrusted=3;
|
static const int psbGotHello=0, psbSentHello=1, psbInMap=2, psbTrusted=3;
|
||||||
static const int psbNoLedgers=4, psbNoTransactions=5, psbDownLevel=6;
|
static const int psbNoLedgers=4, psbNoTransactions=5, psbDownLevel=6;
|
||||||
|
|
||||||
NewcoinAddress mNodePublic; // Node public key of peer.
|
|
||||||
ipPort mIpPort;
|
|
||||||
|
|
||||||
void handleConnect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it);
|
void handleConnect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NewcoinAddress mNodePublic; // Node public key of peer.
|
||||||
|
ipPort mIpPort;
|
||||||
|
uint256 mCookieHash;
|
||||||
|
|
||||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> mSocketSsl;
|
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> mSocketSsl;
|
||||||
|
|
||||||
void handleStart(const boost::system::error_code& error);
|
boost::asio::deadline_timer mVerifyTimer;
|
||||||
|
|
||||||
|
void handleStart(const boost::system::error_code& ecResult);
|
||||||
|
void handleVerifyTimer(const boost::system::error_code& ecResult);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -78,7 +82,7 @@ protected:
|
|||||||
void recvGetLedger(newcoin::TMGetLedger& packet);
|
void recvGetLedger(newcoin::TMGetLedger& packet);
|
||||||
void recvLedger(newcoin::TMLedgerData& packet);
|
void recvLedger(newcoin::TMLedgerData& packet);
|
||||||
|
|
||||||
std::vector<unsigned char> getSessionCookie();
|
void getSessionCookie(std::string& strDst);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef boost::shared_ptr<Peer> pointer;
|
typedef boost::shared_ptr<Peer> pointer;
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ public:
|
|||||||
void start();
|
void start();
|
||||||
|
|
||||||
NewcoinAddress& getNodePublic() { return mNodePublicKey; }
|
NewcoinAddress& getNodePublic() { return mNodePublicKey; }
|
||||||
|
NewcoinAddress& getNodePrivate() { return mNodePrivateKey; }
|
||||||
|
|
||||||
NewcoinAddress addFamily(const std::string& passPhrase, bool lock);
|
NewcoinAddress addFamily(const std::string& passPhrase, bool lock);
|
||||||
NewcoinAddress addFamily(const NewcoinAddress& familySeed, bool lock);
|
NewcoinAddress addFamily(const NewcoinAddress& familySeed, bool lock);
|
||||||
|
|||||||
@@ -38,9 +38,10 @@ message TMHello {
|
|||||||
required uint32 version = 1;
|
required uint32 version = 1;
|
||||||
optional uint32 ledgerIndex = 2;
|
optional uint32 ledgerIndex = 2;
|
||||||
optional uint64 netTime = 3;
|
optional uint64 netTime = 3;
|
||||||
optional bytes nodePublic = 4; // node may opt to remain anonymous
|
optional bytes nodePublic = 4; // node may opt to remain anonymous
|
||||||
optional uint32 ipv4Port = 5;
|
optional bytes nodeProof = 5;
|
||||||
optional bytes closedLedger = 6;
|
optional uint32 ipv4Port = 6;
|
||||||
|
optional bytes closedLedger = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,4 +19,9 @@ boost::posix_time::ptime ptFromSeconds(int iSeconds)
|
|||||||
: ptEpoch() + boost::posix_time::seconds(iSeconds);
|
: ptEpoch() + boost::posix_time::seconds(iSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char charHex(int iDigit)
|
||||||
|
{
|
||||||
|
return iDigit < 10 ? '0' + iDigit : 'A' - 10 + iDigit;
|
||||||
|
}
|
||||||
|
|
||||||
// vim:ts=4
|
// vim:ts=4
|
||||||
|
|||||||
24
src/utils.h
24
src/utils.h
@@ -22,6 +22,30 @@ std::string strJoin(Iterator first, Iterator last, std::string strSeperator)
|
|||||||
|
|
||||||
return ossValues.str();
|
return ossValues.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char charHex(int iDigit);
|
||||||
|
|
||||||
|
template<class Iterator>
|
||||||
|
void strHex(std::string& strDst, Iterator first, int iSize)
|
||||||
|
{
|
||||||
|
strDst.resize(iSize*2);
|
||||||
|
|
||||||
|
for (int i = 0; i < iSize; i++) {
|
||||||
|
unsigned char c = *first++;
|
||||||
|
|
||||||
|
strDst[i*2] = charHex(c >> 4);
|
||||||
|
strDst[i*2+1] = charHex(c & 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void strHex(std::string& strDst, const std::string& strSrc) {
|
||||||
|
strHex(strDst, strSrc.begin(), strSrc.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void strHex(std::string& strDst, const std::vector<unsigned char> vchData) {
|
||||||
|
strHex(strDst, vchData.begin(), vchData.size());
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// vim:ts=4
|
// vim:ts=4
|
||||||
|
|||||||
Reference in New Issue
Block a user