Christoph Jentzsch
10 years ago
23 changed files with 696 additions and 319 deletions
@ -0,0 +1,47 @@ |
|||
/*
|
|||
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 Interface.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "Interface.h" |
|||
|
|||
#include <libdevcore/Log.h> |
|||
#include <libp2p/All.h> |
|||
#include "WhisperHost.h" |
|||
using namespace std; |
|||
using namespace dev; |
|||
using namespace dev::p2p; |
|||
using namespace dev::shh; |
|||
|
|||
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] " |
|||
|
|||
bool MessageFilter::matches(Message const& _m) const |
|||
{ |
|||
for (auto const& t: m_topicMasks) |
|||
{ |
|||
if (t.first.size() != t.second.size() || _m.topic.size() < t.first.size()) |
|||
continue; |
|||
for (unsigned i = 0; i < t.first.size(); ++i) |
|||
if (((t.first[i] ^ _m.topic[i]) & t.second[i]) != 0) |
|||
goto NEXT; |
|||
return true; |
|||
NEXT:; |
|||
} |
|||
return false; |
|||
} |
@ -0,0 +1,132 @@ |
|||
/*
|
|||
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 WhisperHost.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <mutex> |
|||
#include <array> |
|||
#include <set> |
|||
#include <memory> |
|||
#include <utility> |
|||
#include <libdevcore/RLP.h> |
|||
#include <libdevcore/Guards.h> |
|||
#include <libdevcrypto/SHA3.h> |
|||
#include "Common.h" |
|||
#include "Message.h" |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace shh |
|||
{ |
|||
|
|||
class MessageFilter |
|||
{ |
|||
public: |
|||
MessageFilter() {} |
|||
MessageFilter(std::vector<std::pair<bytes, bytes> > const& _m): m_topicMasks(_m) {} |
|||
MessageFilter(RLP const& _r): m_topicMasks((std::vector<std::pair<bytes, bytes>>)_r) {} |
|||
|
|||
void fillStream(RLPStream& _s) const { _s << m_topicMasks; } |
|||
h256 sha3() const { RLPStream s; fillStream(s); return dev::eth::sha3(s.out()); } |
|||
|
|||
bool matches(Message const& _m) const; |
|||
|
|||
private: |
|||
std::vector<std::pair<bytes, bytes> > m_topicMasks; |
|||
}; |
|||
|
|||
struct InstalledFilter |
|||
{ |
|||
InstalledFilter(MessageFilter const& _f): filter(_f) {} |
|||
|
|||
MessageFilter filter; |
|||
unsigned refCount = 1; |
|||
}; |
|||
|
|||
struct ClientWatch |
|||
{ |
|||
ClientWatch() {} |
|||
explicit ClientWatch(h256 _id): id(_id) {} |
|||
|
|||
h256 id; |
|||
h256s changes; |
|||
}; |
|||
|
|||
class Interface |
|||
{ |
|||
public: |
|||
virtual ~Interface() {} |
|||
|
|||
virtual void inject(Message const& _m, WhisperPeer* _from = nullptr) = 0; |
|||
|
|||
virtual unsigned installWatch(MessageFilter const& _filter) = 0; |
|||
virtual unsigned installWatch(h256 _filterId) = 0; |
|||
virtual void uninstallWatch(unsigned _watchId) = 0; |
|||
virtual h256s peekWatch(unsigned _watchId) const = 0; |
|||
virtual h256s checkWatch(unsigned _watchId) = 0; |
|||
|
|||
virtual Message message(h256 _m) const = 0; |
|||
|
|||
virtual void sendRaw(bytes const& _payload, bytes const& _topic, unsigned _ttl) = 0; |
|||
}; |
|||
|
|||
struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; |
|||
#define cwatshh dev::LogOutputStream<shh::WatshhChannel, true>() |
|||
|
|||
} |
|||
} |
|||
/*
|
|||
namespace std { void swap(shh::Watch& _a, shh::Watch& _b); } |
|||
|
|||
namespace shh |
|||
{ |
|||
|
|||
class Watch: public boost::noncopyable |
|||
{ |
|||
friend void std::swap(Watch& _a, Watch& _b); |
|||
|
|||
public: |
|||
Watch() {} |
|||
Watch(Whisper& _c, h256 _f): m_c(&_c), m_id(_c.installWatch(_f)) {} |
|||
Watch(Whisper& _c, MessageFilter const& _tf): m_c(&_c), m_id(_c.installWatch(_tf)) {} |
|||
~Watch() { if (m_c) m_c->uninstallWatch(m_id); } |
|||
|
|||
bool check() { return m_c ? m_c->checkWatch(m_id) : false; } |
|||
bool peek() { return m_c ? m_c->peekWatch(m_id) : false; } |
|||
|
|||
private: |
|||
Whisper* m_c; |
|||
unsigned m_id; |
|||
}; |
|||
|
|||
} |
|||
|
|||
namespace shh |
|||
{ |
|||
|
|||
inline void swap(shh::Watch& _a, shh::Watch& _b) |
|||
{ |
|||
swap(_a.m_c, _b.m_c); |
|||
swap(_a.m_id, _b.m_id); |
|||
} |
|||
|
|||
} |
|||
*/ |
@ -0,0 +1,28 @@ |
|||
/*
|
|||
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 Message.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "Message.h" |
|||
|
|||
using namespace std; |
|||
using namespace dev; |
|||
using namespace dev::p2p; |
|||
using namespace dev::shh; |
|||
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] " |
@ -0,0 +1,63 @@ |
|||
/*
|
|||
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 Message.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <mutex> |
|||
#include <array> |
|||
#include <set> |
|||
#include <memory> |
|||
#include <utility> |
|||
#include <libdevcore/RLP.h> |
|||
#include <libdevcore/Guards.h> |
|||
#include <libdevcrypto/SHA3.h> |
|||
#include "Common.h" |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace shh |
|||
{ |
|||
|
|||
struct Message |
|||
{ |
|||
unsigned expiry = 0; |
|||
unsigned ttl = 0; |
|||
bytes topic; // TODO: change to h256
|
|||
bytes payload; |
|||
|
|||
Message() {} |
|||
Message(unsigned _exp, unsigned _ttl, bytes const& _topic, bytes const& _payload): expiry(_exp), ttl(_ttl), topic(_topic), payload(_payload) {} |
|||
Message(RLP const& _m) |
|||
{ |
|||
expiry = _m[0].toInt<unsigned>(); |
|||
ttl = _m[1].toInt<unsigned>(); |
|||
topic = _m[2].toBytes(); |
|||
payload = _m[3].toBytes(); |
|||
} |
|||
|
|||
operator bool () const { return !!expiry; } |
|||
|
|||
void streamOut(RLPStream& _s) const { _s.appendList(4) << expiry << ttl << topic << payload; } |
|||
h256 sha3() const { RLPStream s; streamOut(s); return dev::eth::sha3(s.out()); } |
|||
}; |
|||
|
|||
} |
|||
} |
@ -0,0 +1,123 @@ |
|||
/*
|
|||
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 WhisperHost.cpp
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#include "WhisperHost.h" |
|||
|
|||
#include <libdevcore/Log.h> |
|||
#include <libp2p/All.h> |
|||
using namespace std; |
|||
using namespace dev; |
|||
using namespace dev::p2p; |
|||
using namespace dev::shh; |
|||
|
|||
#define clogS(X) dev::LogOutputStream<X, true>(false) << "| " << std::setw(2) << session()->socketId() << "] " |
|||
|
|||
WhisperHost::WhisperHost() |
|||
{ |
|||
} |
|||
|
|||
WhisperHost::~WhisperHost() |
|||
{ |
|||
} |
|||
|
|||
void WhisperHost::streamMessage(h256 _m, RLPStream& _s) const |
|||
{ |
|||
UpgradableGuard l(x_messages); |
|||
if (m_messages.count(_m)) |
|||
{ |
|||
UpgradeGuard ll(l); |
|||
m_messages.at(_m).streamOut(_s); |
|||
} |
|||
} |
|||
|
|||
void WhisperHost::inject(Message const& _m, WhisperPeer* _p) |
|||
{ |
|||
auto h = _m.sha3(); |
|||
{ |
|||
UpgradableGuard l(x_messages); |
|||
if (m_messages.count(h)) |
|||
return; |
|||
UpgradeGuard ll(l); |
|||
m_messages[h] = _m; |
|||
} |
|||
|
|||
if (_p) |
|||
{ |
|||
Guard l(m_filterLock); |
|||
for (auto const& f: m_filters) |
|||
if (f.second.filter.matches(_m)) |
|||
noteChanged(h, f.first); |
|||
} |
|||
|
|||
for (auto& i: peers()) |
|||
if (i->cap<WhisperPeer>().get() == _p) |
|||
i->addRating(1); |
|||
else |
|||
i->cap<WhisperPeer>()->noteNewMessage(h, _m); |
|||
} |
|||
|
|||
void WhisperHost::noteChanged(h256 _messageHash, h256 _filter) |
|||
{ |
|||
for (auto& i: m_watches) |
|||
if (i.second.id == _filter) |
|||
{ |
|||
cwatshh << "!!!" << i.first << i.second.id; |
|||
i.second.changes.push_back(_messageHash); |
|||
} |
|||
} |
|||
|
|||
unsigned WhisperHost::installWatch(h256 _h) |
|||
{ |
|||
auto ret = m_watches.size() ? m_watches.rbegin()->first + 1 : 0; |
|||
m_watches[ret] = ClientWatch(_h); |
|||
cwatshh << "+++" << ret << _h; |
|||
return ret; |
|||
} |
|||
|
|||
unsigned WhisperHost::installWatch(shh::MessageFilter const& _f) |
|||
{ |
|||
Guard l(m_filterLock); |
|||
|
|||
h256 h = _f.sha3(); |
|||
|
|||
if (!m_filters.count(h)) |
|||
m_filters.insert(make_pair(h, _f)); |
|||
|
|||
return installWatch(h); |
|||
} |
|||
|
|||
void WhisperHost::uninstallWatch(unsigned _i) |
|||
{ |
|||
cwatshh << "XXX" << _i; |
|||
|
|||
Guard l(m_filterLock); |
|||
|
|||
auto it = m_watches.find(_i); |
|||
if (it == m_watches.end()) |
|||
return; |
|||
auto id = it->second.id; |
|||
m_watches.erase(it); |
|||
|
|||
auto fit = m_filters.find(id); |
|||
if (fit != m_filters.end()) |
|||
if (!--fit->second.refCount) |
|||
m_filters.erase(fit); |
|||
} |
@ -0,0 +1,77 @@ |
|||
/*
|
|||
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 WhisperHost.h
|
|||
* @author Gav Wood <i@gavwood.com> |
|||
* @date 2014 |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <mutex> |
|||
#include <array> |
|||
#include <set> |
|||
#include <memory> |
|||
#include <utility> |
|||
#include <libdevcore/RLP.h> |
|||
#include <libdevcore/Guards.h> |
|||
#include <libdevcrypto/SHA3.h> |
|||
#include "Common.h" |
|||
#include "WhisperPeer.h" |
|||
#include "Interface.h" |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace shh |
|||
{ |
|||
|
|||
class WhisperHost: public HostCapability<WhisperPeer>, public Interface |
|||
{ |
|||
friend class WhisperPeer; |
|||
|
|||
public: |
|||
WhisperHost(); |
|||
virtual ~WhisperHost(); |
|||
|
|||
unsigned protocolVersion() const { return 0; } |
|||
|
|||
virtual void inject(Message const& _m, WhisperPeer* _from = nullptr); |
|||
|
|||
virtual unsigned installWatch(MessageFilter const& _filter); |
|||
virtual unsigned installWatch(h256 _filterId); |
|||
virtual void uninstallWatch(unsigned _watchId); |
|||
virtual h256s peekWatch(unsigned _watchId) const { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } } |
|||
virtual h256s checkWatch(unsigned _watchId) { dev::Guard l(m_filterLock); h256s ret; try { ret = m_watches.at(_watchId).changes; m_watches.at(_watchId).changes.clear(); } catch (...) {} return ret; } |
|||
|
|||
virtual Message message(h256 _m) const { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Message(); } } |
|||
|
|||
virtual void sendRaw(bytes const& _payload, bytes const& _topic, unsigned _ttl) { inject(Message(time(0) + _ttl, _ttl, _topic, _payload)); } |
|||
|
|||
private: |
|||
void streamMessage(h256 _m, RLPStream& _s) const; |
|||
|
|||
void noteChanged(h256 _messageHash, h256 _filter); |
|||
|
|||
mutable dev::SharedMutex x_messages; |
|||
std::map<h256, Message> m_messages; |
|||
|
|||
mutable dev::Mutex m_filterLock; |
|||
std::map<h256, InstalledFilter> m_filters; |
|||
std::map<unsigned, ClientWatch> m_watches; |
|||
}; |
|||
|
|||
} |
|||
} |
Loading…
Reference in new issue