diff --git a/libwebthree/WebThree.h b/libwebthree/WebThree.h index cae6fd6f8..20789517d 100644 --- a/libwebthree/WebThree.h +++ b/libwebthree/WebThree.h @@ -32,7 +32,7 @@ #include #include -#include +#include #include namespace dev diff --git a/libwhisper/Interface.cpp b/libwhisper/Interface.cpp new file mode 100644 index 000000000..4ccf85689 --- /dev/null +++ b/libwhisper/Interface.cpp @@ -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 . +*/ +/** @file Interface.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Interface.h" + +#include +#include +#include "WhisperHost.h" +using namespace std; +using namespace dev; +using namespace dev::p2p; +using namespace dev::shh; + +#define clogS(X) dev::LogOutputStream(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; +} diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h new file mode 100644 index 000000000..e9b822cba --- /dev/null +++ b/libwhisper/Interface.h @@ -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 . +*/ +/** @file WhisperHost.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include "Common.h" +#include "Message.h" + +namespace dev +{ +namespace shh +{ + +class MessageFilter +{ +public: + MessageFilter() {} + MessageFilter(std::vector > const& _m): m_topicMasks(_m) {} + MessageFilter(RLP const& _r): m_topicMasks((std::vector>)_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 > 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() + +} +} +/* +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); +} + +} +*/ diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp new file mode 100644 index 000000000..d7fed1811 --- /dev/null +++ b/libwhisper/Message.cpp @@ -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 . +*/ +/** @file Message.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "Message.h" + +using namespace std; +using namespace dev; +using namespace dev::p2p; +using namespace dev::shh; +#define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << session()->socketId() << "] " diff --git a/libwhisper/Message.h b/libwhisper/Message.h new file mode 100644 index 000000000..232e4133b --- /dev/null +++ b/libwhisper/Message.h @@ -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 . +*/ +/** @file Message.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include "Common.h" + +namespace dev +{ +namespace shh +{ + +struct Message +{ + unsigned expiry = 0; + unsigned ttl = 0; + bytes topic; + 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(); + ttl = _m[1].toInt(); + 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()); } +}; + +} +} diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp new file mode 100644 index 000000000..e5e32e72f --- /dev/null +++ b/libwhisper/WhisperHost.cpp @@ -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 . +*/ +/** @file WhisperHost.cpp + * @author Gav Wood + * @date 2014 + */ + +#include "WhisperHost.h" + +#include +#include +using namespace std; +using namespace dev; +using namespace dev::p2p; +using namespace dev::shh; + +#define clogS(X) dev::LogOutputStream(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().get() == _p) + i->addRating(1); + else + i->cap()->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); +} diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h new file mode 100644 index 000000000..5bf1b3ca2 --- /dev/null +++ b/libwhisper/WhisperHost.h @@ -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 . +*/ +/** @file WhisperHost.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include "Common.h" +#include "WhisperPeer.h" +#include "Interface.h" + +namespace dev +{ +namespace shh +{ + +class WhisperHost: public HostCapability, public Interface +{ + friend class WhisperPeer; + +public: + WhisperHost(); + virtual ~WhisperHost(); + + unsigned protocolVersion() const { return 0; } + + void inject(Message const& _m, WhisperPeer* _from = nullptr); + + unsigned installWatch(MessageFilter const& _filter); + unsigned installWatch(h256 _filterId); + void uninstallWatch(unsigned _watchId); + h256s peekWatch(unsigned _watchId) const { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } } + 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; } + + Message message(h256 _m) const { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Message(); } } + + 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 m_messages; + + mutable dev::Mutex m_filterLock; + std::map m_filters; + std::map m_watches; +}; + +} +} diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index a1f9c99b8..4baccdf9c 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file Whisper.cpp +/** @file WhisperPeer.cpp * @author Gav Wood * @date 2014 */ @@ -23,11 +23,11 @@ #include #include +#include "WhisperHost.h" using namespace std; using namespace dev; using namespace dev::p2p; using namespace dev::shh; - #define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << session()->socketId() << "] " WhisperPeer::WhisperPeer(Session* _s, HostCapabilityFace* _h): Capability(_s, _h) @@ -108,110 +108,3 @@ void WhisperPeer::noteNewMessage(h256 _h, Message const& _m) Guard l(x_unseen); m_unseen[rating(_m)] = _h; } - -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().get() == _p) - i->addRating(1); - else - i->cap()->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); - } -} - -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; -} - -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); -} diff --git a/libwhisper/WhisperPeer.h b/libwhisper/WhisperPeer.h index 94d3233c1..b3fe2701b 100644 --- a/libwhisper/WhisperPeer.h +++ b/libwhisper/WhisperPeer.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file Whisper.h +/** @file WhisperPeer.h * @author Gav Wood * @date 2014 */ @@ -30,6 +30,7 @@ #include #include #include "Common.h" +#include "Message.h" namespace dev { @@ -41,29 +42,6 @@ using p2p::HostCapabilityFace; using p2p::HostCapability; using p2p::Capability; -struct Message -{ - unsigned expiry = 0; - unsigned ttl = 0; - bytes topic; - 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(); - ttl = _m[1].toInt(); - 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()); } -}; - /** */ class WhisperPeer: public Capability @@ -90,133 +68,5 @@ private: std::map m_unseen; ///< Rated according to what they want. }; -class MessageFilter -{ -public: - MessageFilter() {} - MessageFilter(std::vector > const& _m): m_topicMasks(_m) {} - MessageFilter(RLP const& _r): m_topicMasks((std::vector>)_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 > 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; -}; - -class WhisperHost: public HostCapability, public Interface -{ - friend class WhisperPeer; - -public: - WhisperHost(); - virtual ~WhisperHost(); - - unsigned protocolVersion() const { return 0; } - - void inject(Message const& _m, WhisperPeer* _from = nullptr); - - unsigned installWatch(MessageFilter const& _filter); - unsigned installWatch(h256 _filterId); - void uninstallWatch(unsigned _watchId); - h256s peekWatch(unsigned _watchId) const { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } } - 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; } - - Message message(h256 _m) const { try { dev::ReadGuard l(x_messages); return m_messages.at(_m); } catch (...) { return Message(); } } - - 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 m_messages; - - mutable dev::Mutex m_filterLock; - std::map m_filters; - std::map m_watches; -}; - -struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; -#define cwatshh dev::LogOutputStream() - -class Watch; - } } -/* -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); -} - -} -*/