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