2016-08-16 16:51:22 +02:00
|
|
|
/*
|
2017-11-09 19:34:51 +01:00
|
|
|
* This file is part of the Flowee project
|
2026-05-19 18:34:36 +02:00
|
|
|
* Copyright (C) 2016-2026 Tom Zander <tom@flowee.org>
|
2016-08-16 16:51:22 +02:00
|
|
|
*
|
|
|
|
|
* This program 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.
|
|
|
|
|
*
|
|
|
|
|
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
2024-01-22 19:32:15 +01:00
|
|
|
#ifndef FLOWEE_NETWORKMANAGER_P_H
|
|
|
|
|
#define FLOWEE_NETWORKMANAGER_P_H
|
2016-08-16 16:51:22 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* WARNING USAGE OF THIS HEADER IS RESTRICTED.
|
|
|
|
|
* This Header file is part of the private API and is meant to be used solely by the NetworkManager component.
|
|
|
|
|
*
|
|
|
|
|
* Usage of this API will likely mean your code will break in interesting ways in the future,
|
|
|
|
|
* or even stop to compile.
|
|
|
|
|
*
|
|
|
|
|
* YOU HAVE BEEN WARNED!!
|
|
|
|
|
*/
|
|
|
|
|
|
2025-02-11 20:16:32 +01:00
|
|
|
#include <boost/version.hpp>
|
|
|
|
|
#if BOOST_VERSION > 107400
|
|
|
|
|
# define FLOWEE_NET_SSL 1
|
|
|
|
|
# include <boost/asio/registered_buffer.hpp>
|
|
|
|
|
# include <boost/asio/ssl.hpp>
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-08-16 16:51:22 +02:00
|
|
|
#include "NetworkEndPoint.h"
|
2019-11-29 10:59:58 +01:00
|
|
|
#include "NetworkConnection.h"
|
2016-08-16 16:51:22 +02:00
|
|
|
#include <Message.h>
|
|
|
|
|
#include <streaming/BufferPool.h>
|
|
|
|
|
|
|
|
|
|
#include <list>
|
2020-05-10 00:46:41 +02:00
|
|
|
#include <deque>
|
2021-07-15 13:10:05 +02:00
|
|
|
#include <mutex>
|
2016-08-16 16:51:22 +02:00
|
|
|
#include <atomic>
|
2026-05-18 09:38:41 +02:00
|
|
|
#include <limits>
|
|
|
|
|
#include <stdexcept>
|
2020-03-28 22:49:53 +01:00
|
|
|
#include <boost/date_time/posix_time/ptime.hpp>
|
|
|
|
|
#include <boost/asio.hpp>
|
2016-08-16 16:51:22 +02:00
|
|
|
|
2019-04-09 17:24:38 +02:00
|
|
|
class NetworkServiceBase;
|
2019-11-29 10:59:58 +01:00
|
|
|
class NetworkManagerPrivate;
|
2016-08-16 16:51:22 +02:00
|
|
|
|
|
|
|
|
using boost::asio::ip::tcp;
|
|
|
|
|
|
2020-09-17 20:53:56 +02:00
|
|
|
/**
|
|
|
|
|
* Ringbuffer is specially crafted for the NetworkManager to have a zero-alloc buffer.
|
|
|
|
|
* The special part about this ringbuffer is that it allows you to have a read pointer
|
|
|
|
|
* that you use to get items out which you then mark as read. This marking it as read
|
|
|
|
|
* only affects your ability to read the next one.
|
|
|
|
|
* Marking something as read does not mark that item as deletable. We still keep a reference
|
|
|
|
|
* to the item! Especially useful if the item is a shared-pointer.
|
|
|
|
|
* Then at some later point we allow removing of items. Either using removeTip() or using
|
|
|
|
|
* removeAllRead()
|
|
|
|
|
*/
|
2019-03-23 19:32:11 +01:00
|
|
|
template<class V>
|
|
|
|
|
class RingBuffer
|
|
|
|
|
{
|
|
|
|
|
public:
|
2026-05-18 09:38:41 +02:00
|
|
|
RingBuffer(size_t size) : m_array(size + 1), NumItems(static_cast<int>(size + 1)) {
|
|
|
|
|
assert(size > 0);
|
|
|
|
|
assert(size < static_cast<size_t>(std::numeric_limits<int>::max()));
|
|
|
|
|
}
|
2020-05-09 19:58:44 +02:00
|
|
|
|
2019-03-23 19:32:11 +01:00
|
|
|
void append(const V &v) {
|
2026-05-18 09:38:41 +02:00
|
|
|
assert(!isFull());
|
|
|
|
|
if (isFull())
|
|
|
|
|
throw std::runtime_error("RingBuffer is full");
|
2019-03-23 19:32:11 +01:00
|
|
|
m_array[m_next] = v;
|
|
|
|
|
if (++m_next >= NumItems)
|
|
|
|
|
m_next = 0;
|
|
|
|
|
assert(m_next != m_first);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// total amount of space in this ringbuffer
|
2026-05-18 09:38:41 +02:00
|
|
|
inline int reserved() const { return NumItems - 1; }
|
2019-03-23 19:32:11 +01:00
|
|
|
/// Amount of items filled
|
|
|
|
|
inline int count() const {
|
|
|
|
|
return m_next - m_first + (m_next < m_first /* we went circular */ ? NumItems : 0);
|
|
|
|
|
}
|
|
|
|
|
/// reserved minus usage
|
|
|
|
|
int slotsAvailable() const {
|
|
|
|
|
return reserved() - count();
|
|
|
|
|
}
|
|
|
|
|
/// alias for count()
|
|
|
|
|
inline int size() const { return count(); }
|
|
|
|
|
inline bool isEmpty() const { return m_first == m_next; }
|
|
|
|
|
|
|
|
|
|
/// the tip is the first inserted, but not yet removed item.
|
|
|
|
|
inline const V &tip() const {
|
|
|
|
|
assert(m_first != m_next); // aka empty
|
|
|
|
|
return m_array[m_first];
|
|
|
|
|
}
|
|
|
|
|
/// remove the tip, moving the tip to the next item.
|
|
|
|
|
inline void removeTip() {
|
|
|
|
|
assert(m_first != m_next); // aka empty
|
|
|
|
|
m_array[m_first] = V();
|
|
|
|
|
if (++m_first >= NumItems)
|
|
|
|
|
m_first = 0;
|
|
|
|
|
|
|
|
|
|
if (m_first <= m_next) // standard linear list
|
|
|
|
|
m_readIndex = std::max(m_readIndex, m_first);
|
|
|
|
|
else if (m_readIndex < m_first && m_readIndex > m_next) // circular list state
|
|
|
|
|
m_readIndex = m_first;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// an item just inserted is unread, we read in the same order as insertion.
|
|
|
|
|
inline void markRead(int count = 1) {
|
|
|
|
|
assert(count < NumItems);
|
|
|
|
|
assert(count > 0);
|
|
|
|
|
m_readIndex += count;
|
|
|
|
|
while (m_readIndex >= NumItems)
|
|
|
|
|
m_readIndex -= NumItems;
|
2019-03-24 11:43:43 +01:00
|
|
|
assert(m_first < m_next && m_readIndex >= m_first && m_readIndex <= m_next
|
|
|
|
|
|| (m_first > m_next && (m_readIndex >= m_first || m_readIndex <= m_next)));
|
2019-03-23 19:32:11 +01:00
|
|
|
}
|
2019-04-11 14:57:00 +02:00
|
|
|
|
|
|
|
|
inline void removeAllRead() {
|
|
|
|
|
while (m_first != m_readIndex) {
|
|
|
|
|
m_array[m_first] = V();
|
|
|
|
|
if (++m_first >= NumItems)
|
|
|
|
|
m_first = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-23 19:32:11 +01:00
|
|
|
/// first not yet read item.
|
|
|
|
|
inline const V &unreadTip() const {
|
2019-03-24 11:43:43 +01:00
|
|
|
assert(m_first < m_next && m_readIndex >= m_first && m_readIndex < m_next
|
|
|
|
|
|| (m_first > m_next && (m_readIndex >= m_first || m_readIndex < m_next)));
|
2019-03-23 19:32:11 +01:00
|
|
|
return m_array[m_readIndex];
|
|
|
|
|
}
|
|
|
|
|
/// returns true, like isEmpty(), when there are no unread items.
|
|
|
|
|
inline bool isRead() const { return m_readIndex == m_next; }
|
|
|
|
|
/// Return true if there are items inserted, but not yet marked read (inverse of isRead())
|
|
|
|
|
inline bool hasUnread() const { return m_readIndex != m_next; }
|
2026-05-18 09:38:41 +02:00
|
|
|
inline bool isFull() const { return (m_next + 1) % NumItems == m_first; }
|
2019-03-23 19:32:11 +01:00
|
|
|
|
|
|
|
|
inline bool hasItemsMarkedRead() const {
|
|
|
|
|
return m_readIndex != m_first;
|
|
|
|
|
}
|
|
|
|
|
inline void markAllUnread() {
|
|
|
|
|
m_readIndex = m_first;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// clear all data.
|
|
|
|
|
inline void clear() {
|
|
|
|
|
const int end = count() + m_first;
|
|
|
|
|
for (int i = m_first; i < end; ++i) {
|
|
|
|
|
m_array[i % NumItems] = V();
|
|
|
|
|
}
|
|
|
|
|
m_first = 0;
|
|
|
|
|
m_readIndex = 0;
|
|
|
|
|
m_next = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
/* We append at 'next', increasing it to point to the first unused one.
|
|
|
|
|
* As this is a FIFO, we move the m_first and m_readIndex as we process (and remove) items,
|
|
|
|
|
* if we reach the 'next' position we have an empty buffer.
|
|
|
|
|
*
|
|
|
|
|
* Write | variable | Read
|
|
|
|
|
*
|
|
|
|
|
* m_first -> tip()
|
|
|
|
|
* |
|
|
|
|
|
* markRead() -> m_readIndex -> unreadTip()
|
|
|
|
|
* |
|
|
|
|
|
* last-item
|
|
|
|
|
* append() -> m_next -> nullptr
|
|
|
|
|
*/
|
2020-05-09 19:58:44 +02:00
|
|
|
std::vector<V> m_array;
|
2019-03-23 19:32:11 +01:00
|
|
|
int m_first = 0;
|
|
|
|
|
int m_readIndex = 0;
|
|
|
|
|
int m_next = 0; // last plus one
|
2026-05-18 09:38:41 +02:00
|
|
|
const int NumItems;
|
2019-03-23 19:32:11 +01:00
|
|
|
};
|
|
|
|
|
|
2024-07-23 20:02:14 +02:00
|
|
|
class NetworkManagerSocketProxyBase
|
|
|
|
|
{
|
|
|
|
|
public:
|
2024-07-25 11:54:05 +02:00
|
|
|
NetworkManagerSocketProxyBase() = default;
|
|
|
|
|
virtual ~NetworkManagerSocketProxyBase() = default;
|
2024-07-23 20:02:14 +02:00
|
|
|
|
|
|
|
|
virtual boost::asio::ip::tcp::endpoint remote_endpoint() const = 0;
|
|
|
|
|
|
2024-08-21 16:53:34 +02:00
|
|
|
virtual void newConnection(const tcp::endpoint &to, const std::shared_ptr<NetworkManagerConnection> &owner,
|
2024-07-23 20:02:14 +02:00
|
|
|
const std::function<void(const boost::system::error_code &error)> &callback) = 0;
|
|
|
|
|
|
|
|
|
|
virtual void async_write(const std::vector<Streaming::ConstBuffer> &data,
|
|
|
|
|
const std::function<void(const boost::system::error_code &error,std::size_t bytes_transferred)> &callback) = 0;
|
|
|
|
|
|
|
|
|
|
virtual void async_receive(Streaming::BufferPool &pool,
|
|
|
|
|
const std::function<void(const boost::system::error_code &error,std::size_t bytes_transferred)> &callback) = 0;
|
|
|
|
|
|
|
|
|
|
virtual bool is_open() const = 0;
|
|
|
|
|
virtual void close() = 0;
|
2024-08-21 17:58:45 +02:00
|
|
|
|
|
|
|
|
// should reflect the EndPoint.encrypted boolean
|
|
|
|
|
virtual bool isEncrypted() const = 0;
|
2025-02-11 19:23:14 +01:00
|
|
|
|
|
|
|
|
NetworkManagerConnection *q = nullptr;
|
2024-07-23 20:02:14 +02:00
|
|
|
};
|
|
|
|
|
|
2019-06-03 21:42:37 +02:00
|
|
|
class NetworkManagerConnection : public std::enable_shared_from_this<NetworkManagerConnection>
|
2016-08-16 16:51:22 +02:00
|
|
|
{
|
|
|
|
|
public:
|
2020-03-26 19:28:24 +01:00
|
|
|
enum MessageHeaderType {
|
|
|
|
|
FloweeNative,
|
|
|
|
|
LegacyP2P
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-23 20:02:14 +02:00
|
|
|
NetworkManagerConnection(const std::shared_ptr<NetworkManagerPrivate> &parent, NetworkManagerSocketProxyBase *socketProxy, int connectionId);
|
2024-08-04 14:02:53 +02:00
|
|
|
NetworkManagerConnection(const std::shared_ptr<NetworkManagerPrivate> &parent, const EndPoint &remote);
|
2024-07-23 20:02:14 +02:00
|
|
|
~NetworkManagerConnection();
|
|
|
|
|
|
2016-08-16 16:51:22 +02:00
|
|
|
/// Connects to remote (async)
|
|
|
|
|
void connect();
|
|
|
|
|
|
|
|
|
|
int nextCallbackId();
|
|
|
|
|
|
|
|
|
|
/// unregister a NetworkConnection. Calls have to be from the strand.
|
|
|
|
|
void removeAllCallbacksFor(int id);
|
|
|
|
|
|
|
|
|
|
void queueMessage(const Message &message, NetworkConnection::MessagePriority priority);
|
|
|
|
|
|
|
|
|
|
inline bool isConnected() const {
|
2019-06-03 21:42:37 +02:00
|
|
|
return m_isConnected;
|
2016-08-16 16:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline const EndPoint &endPoint() const {
|
|
|
|
|
return m_remote;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-10 00:46:41 +02:00
|
|
|
void setEndPoint(const EndPoint &ep) {
|
|
|
|
|
m_remote = ep;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-16 16:51:22 +02:00
|
|
|
/// add callback, calls have to be on the strand.
|
2020-05-07 18:26:41 +02:00
|
|
|
void addOnConnectedCallback(int id, std::function<void(const EndPoint&)> callback);
|
2016-08-16 16:51:22 +02:00
|
|
|
/// add callback, calls have to be on the strand.
|
2020-05-07 18:26:41 +02:00
|
|
|
void addOnDisconnectedCallback(int id, std::function<void(const EndPoint&)> callback);
|
2016-08-16 16:51:22 +02:00
|
|
|
/// add callback, calls have to be on the strand.
|
2020-05-07 18:26:41 +02:00
|
|
|
void addOnIncomingMessageCallback(int id, std::function<void(const Message&)> callback);
|
2020-04-01 20:21:02 +02:00
|
|
|
/// add callback, calls have to be on the strand.
|
2020-05-07 18:26:41 +02:00
|
|
|
void addOnError(int id, std::function<void(int,const boost::system::error_code&)> callback);
|
2016-08-16 16:51:22 +02:00
|
|
|
|
2022-11-03 23:40:31 +01:00
|
|
|
void setLoginCreator(const std::function<Message()> &creator);
|
|
|
|
|
|
2016-08-16 16:51:22 +02:00
|
|
|
/// forcably shut down the connection, soon you should no longer reference this object
|
2020-05-07 18:26:41 +02:00
|
|
|
void shutdown();
|
2016-08-16 16:51:22 +02:00
|
|
|
|
|
|
|
|
/// only incoming connections need accepting.
|
2021-06-27 11:44:26 +02:00
|
|
|
void accept(NetworkConnection::AcceptLimit limit);
|
2016-08-16 16:51:22 +02:00
|
|
|
|
|
|
|
|
inline void disconnect() {
|
|
|
|
|
close(false);
|
2021-02-17 22:59:35 +01:00
|
|
|
if (m_priorityMessageQueue)
|
|
|
|
|
m_priorityMessageQueue->clear();
|
|
|
|
|
if (m_messageQueue)
|
|
|
|
|
m_messageQueue->clear();
|
2016-08-16 16:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-10 00:46:41 +02:00
|
|
|
void recycleConnection();
|
|
|
|
|
|
2020-03-28 22:49:53 +01:00
|
|
|
boost::asio::io_context::strand m_strand;
|
2016-08-16 16:51:22 +02:00
|
|
|
|
|
|
|
|
/// move a call to the thread that the strand represents
|
|
|
|
|
void runOnStrand(const std::function<void()> &function);
|
|
|
|
|
|
|
|
|
|
inline bool acceptedConnection() const {
|
|
|
|
|
return m_acceptedConnection;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-01 20:21:02 +02:00
|
|
|
void setMessageHeaderType(MessageHeaderType messageHeaderType);
|
|
|
|
|
|
2016-08-16 16:51:22 +02:00
|
|
|
void punish(int amount);
|
2020-09-17 20:58:02 +02:00
|
|
|
void setMessageQueueSizes(int main, int priority);
|
2020-05-10 00:46:41 +02:00
|
|
|
void close(bool reconnect = true); // close down connection
|
2024-08-21 16:53:34 +02:00
|
|
|
void setCertificate(const Streaming::ConstBuffer &cert);
|
2016-08-16 16:51:22 +02:00
|
|
|
|
2020-05-09 19:58:44 +02:00
|
|
|
short m_punishment = 0; // aka ban-sore
|
2020-03-26 19:28:24 +01:00
|
|
|
// used to check incoming messages being actually for us
|
|
|
|
|
MessageHeaderType m_messageHeaderType = FloweeNative;
|
2016-08-16 16:51:22 +02:00
|
|
|
|
2020-04-01 20:21:02 +02:00
|
|
|
std::shared_ptr<NetworkManagerPrivate> d;
|
|
|
|
|
|
2024-08-21 17:58:45 +02:00
|
|
|
// called from helper classes...
|
2024-08-21 19:37:13 +02:00
|
|
|
void errorDetected(const boost::system::error_code &error);
|
2024-08-21 17:58:45 +02:00
|
|
|
void requestMoreBytes();
|
2024-08-20 22:46:48 +02:00
|
|
|
|
2016-08-16 16:51:22 +02:00
|
|
|
private:
|
|
|
|
|
EndPoint m_remote;
|
|
|
|
|
|
2025-02-11 16:46:21 +01:00
|
|
|
void onAddressResolveComplete(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::results_type results);
|
2016-08-16 16:51:22 +02:00
|
|
|
void onConnectComplete(const boost::system::error_code& error);
|
|
|
|
|
|
|
|
|
|
/// call then to start sending messages to remote. Will do noting if we are already sending messages.
|
|
|
|
|
void runMessageQueue();
|
|
|
|
|
void sentSomeBytes(const boost::system::error_code& error, std::size_t bytes_transferred);
|
2019-03-31 15:13:59 +02:00
|
|
|
void requestMoreBytes_callback(const boost::system::error_code &error);
|
2016-08-16 16:51:22 +02:00
|
|
|
void receivedSomeBytes(const boost::system::error_code& error, std::size_t bytes_transferred);
|
|
|
|
|
|
|
|
|
|
bool processPacket(const std::shared_ptr<char> &buffer, const char *data);
|
2020-03-26 19:28:24 +01:00
|
|
|
bool processLegacyPacket(const std::shared_ptr<char> &buffer, const char *data);
|
2016-08-16 16:51:22 +02:00
|
|
|
void connect_priv(); // thread-unsafe version of connect
|
|
|
|
|
void reconnectWithCheck(const boost::system::error_code& error); // called from the m_reconectDelay timer
|
2020-05-07 18:26:41 +02:00
|
|
|
void finalShutdown();
|
2016-08-16 16:51:22 +02:00
|
|
|
void sendPing(const boost::system::error_code& error);
|
|
|
|
|
void pingTimeout(const boost::system::error_code& error);
|
2020-05-09 19:58:44 +02:00
|
|
|
void allocateBuffers();
|
2016-08-16 16:51:22 +02:00
|
|
|
|
2024-01-22 14:42:27 +01:00
|
|
|
void callOnDisconnectedCallbacks();
|
|
|
|
|
|
2016-08-16 16:51:22 +02:00
|
|
|
inline bool isOutgoing() const {
|
|
|
|
|
return m_remote.announcePort == m_remote.peerPort;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Streaming::ConstBuffer createHeader(const Message &message);
|
|
|
|
|
|
|
|
|
|
std::map<int, std::function<void(const EndPoint&)> > m_onConnectedCallbacks;
|
|
|
|
|
std::map<int, std::function<void(const EndPoint&)> > m_onDisConnectedCallbacks;
|
|
|
|
|
std::map<int, std::function<void(const Message&)> > m_onIncomingMessageCallbacks;
|
2020-04-01 20:21:02 +02:00
|
|
|
std::map<int, std::function<void(int,const boost::system::error_code&)> > m_onErrorCallbacks;
|
2022-11-03 23:40:31 +01:00
|
|
|
std::function<Message()> m_loginMessageCreator;
|
2016-08-16 16:51:22 +02:00
|
|
|
|
2024-07-23 20:02:14 +02:00
|
|
|
NetworkManagerSocketProxyBase *m_socketProxy = nullptr;
|
2016-08-16 16:51:22 +02:00
|
|
|
tcp::resolver m_resolver;
|
|
|
|
|
|
2020-05-09 19:58:44 +02:00
|
|
|
std::unique_ptr<RingBuffer<Message> > m_messageQueue;
|
|
|
|
|
std::unique_ptr<RingBuffer<Message> > m_priorityMessageQueue;
|
|
|
|
|
std::unique_ptr<RingBuffer<Streaming::ConstBuffer> > m_sendQHeaders;
|
2021-06-27 11:42:47 +02:00
|
|
|
int m_messageBytesSend = 0;
|
2016-08-16 16:51:22 +02:00
|
|
|
|
|
|
|
|
Streaming::BufferPool m_receiveStream;
|
|
|
|
|
mutable std::atomic<int> m_lastCallbackId;
|
|
|
|
|
std::atomic<bool> m_isClosingDown;
|
2020-05-09 19:58:44 +02:00
|
|
|
bool m_firstPacket = true;
|
2021-06-27 11:44:26 +02:00
|
|
|
/// The connection that we used to notify of a new incoming connection is the only
|
|
|
|
|
/// one that will get the first message, likely for some authentication feature.
|
2024-09-10 19:06:07 +02:00
|
|
|
bool m_firstMessageIsForAcceptConnection = false;
|
2020-05-09 19:58:44 +02:00
|
|
|
bool m_isConnecting = false;
|
2019-06-03 21:42:37 +02:00
|
|
|
bool m_isConnected;
|
2020-05-09 19:58:44 +02:00
|
|
|
bool m_sendingInProgress = false;
|
|
|
|
|
bool m_acceptedConnection = false;
|
2016-08-16 16:51:22 +02:00
|
|
|
|
2020-09-02 10:57:14 +02:00
|
|
|
int m_queueSizeMain = 2000; // config setting for the ringbuffers sizes
|
|
|
|
|
int m_priorityQueueSize = 20; // ditto
|
2020-09-17 20:58:02 +02:00
|
|
|
// flow-control limits
|
|
|
|
|
/*
|
|
|
|
|
* When on processing the received messages, the send queue reached this size
|
|
|
|
|
* we interrupt and do a quick send.
|
|
|
|
|
*/
|
|
|
|
|
int m_forceSendLimit = 750;
|
|
|
|
|
/*
|
|
|
|
|
* A send-message queue size limit that determines
|
|
|
|
|
* if we throttle waiting on receive, and by how much.
|
|
|
|
|
* Below L1 we don't wait.
|
|
|
|
|
* Below L2 we wait 10ms, below L3 we wait 50ms.
|
|
|
|
|
*/
|
|
|
|
|
int m_throttleReceiveAtSendLimitL1 = 1000;
|
|
|
|
|
int m_throttleReceiveAtSendLimitL2 = 1500;
|
|
|
|
|
int m_throttleReceiveAtSendLimitL3 = 1900;
|
2020-05-09 19:58:44 +02:00
|
|
|
|
|
|
|
|
short m_reconnectStep = 0;
|
2025-10-17 22:13:32 +02:00
|
|
|
boost::asio::system_timer m_reconnectDelay;
|
2016-08-16 16:51:22 +02:00
|
|
|
|
|
|
|
|
// for these I write 'ping' but its 'pong' for server (incoming) connections.
|
2025-10-17 22:13:32 +02:00
|
|
|
boost::asio::system_timer m_pingTimer;
|
2022-04-20 11:41:15 +02:00
|
|
|
boost::posix_time::ptime m_lastPong; // timestamp of the last pong seen by the outgoing connection
|
2025-10-17 22:13:32 +02:00
|
|
|
boost::asio::steady_timer m_sendTimer;
|
2016-08-16 16:51:22 +02:00
|
|
|
Message m_pingMessage;
|
|
|
|
|
|
|
|
|
|
// chunked messages can be recombined.
|
|
|
|
|
Streaming::BufferPool m_chunkedMessageBuffer;
|
2020-05-09 19:58:44 +02:00
|
|
|
int m_chunkedServiceId = -1;
|
|
|
|
|
int m_chunkedMessageId = -1;
|
2019-06-03 21:42:37 +02:00
|
|
|
std::map<int, int> m_chunkedHeaderData;
|
2016-08-16 16:51:22 +02:00
|
|
|
};
|
|
|
|
|
|
2024-07-05 23:54:18 +02:00
|
|
|
|
2024-08-11 18:46:53 +02:00
|
|
|
// NetworkManagerServerBase and its two implementations are the server side part
|
|
|
|
|
// that listens on a network interface and spawning a new connection.
|
|
|
|
|
// The two subclasses mark the difference between a raw socket connection and an ssl-wrapped one.
|
2024-07-05 23:54:18 +02:00
|
|
|
class NetworkManagerServerBase
|
2016-08-16 16:51:22 +02:00
|
|
|
{
|
|
|
|
|
public:
|
2024-08-11 18:46:53 +02:00
|
|
|
/**
|
|
|
|
|
* Constructor.
|
|
|
|
|
* @param parent the link to the NetworkManager
|
|
|
|
|
* @param endpoint which interface to listen on.
|
|
|
|
|
* @param callback to call on creating a connection.
|
|
|
|
|
*/
|
2024-07-05 23:54:18 +02:00
|
|
|
NetworkManagerServerBase(const std::shared_ptr<NetworkManagerPrivate> &parent, tcp::endpoint endpoint, const std::function<void(NetworkConnection&)> &callback);
|
2024-07-25 11:54:05 +02:00
|
|
|
virtual ~NetworkManagerServerBase() = default;
|
2016-08-16 16:51:22 +02:00
|
|
|
|
2024-08-11 18:46:53 +02:00
|
|
|
/// the callback when a connection comes in, will call createNewConnection()
|
2024-08-13 22:52:15 +02:00
|
|
|
void acceptConnection(boost::asio::ip::tcp::socket && socket);
|
2024-07-05 23:54:18 +02:00
|
|
|
virtual void shutdown() = 0;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
virtual void setupCallback() = 0;
|
2024-08-13 22:52:15 +02:00
|
|
|
virtual std::shared_ptr<NetworkManagerConnection> createNewConnection(int connectionId, boost::asio::ip::tcp::socket && socket) = 0;
|
2016-08-16 16:51:22 +02:00
|
|
|
|
|
|
|
|
std::weak_ptr<NetworkManagerPrivate> d;
|
|
|
|
|
tcp::acceptor m_acceptor;
|
2025-02-23 23:49:46 +01:00
|
|
|
tcp::endpoint m_endpoint;
|
2016-08-16 16:51:22 +02:00
|
|
|
std::function<void(NetworkConnection&)> onIncomingConnection; // callback
|
|
|
|
|
};
|
|
|
|
|
|
2025-02-11 20:16:32 +01:00
|
|
|
#ifdef FLOWEE_NET_SSL
|
2024-08-11 18:46:53 +02:00
|
|
|
/// Implements a server that binds and handles ssl connection setup.
|
2024-07-05 23:54:18 +02:00
|
|
|
class NetworkManagerServerSSL : public NetworkManagerServerBase
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
NetworkManagerServerSSL(const std::shared_ptr<NetworkManagerPrivate> &parent, tcp::endpoint endpoint, const std::function<void(NetworkConnection&)> &callback);
|
|
|
|
|
|
2024-08-20 22:46:48 +02:00
|
|
|
void start() {
|
|
|
|
|
setupCallback();
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-05 23:54:18 +02:00
|
|
|
void shutdown() override;
|
|
|
|
|
|
2024-07-20 18:21:29 +02:00
|
|
|
void setCertificateChain(const Streaming::ConstBuffer &certificateChain);
|
|
|
|
|
void setPrivateKey(const Streaming::ConstBuffer &privateKey);
|
2024-08-20 22:46:48 +02:00
|
|
|
void setDHTemp(const Streaming::ConstBuffer &dhTemp);
|
2024-07-20 18:21:29 +02:00
|
|
|
|
2024-07-05 23:54:18 +02:00
|
|
|
protected:
|
|
|
|
|
void setupCallback() override;
|
2024-08-13 22:52:15 +02:00
|
|
|
std::shared_ptr<NetworkManagerConnection> createNewConnection(int connectionId, boost::asio::ip::tcp::socket && socket) override;
|
2024-07-05 23:54:18 +02:00
|
|
|
|
|
|
|
|
private:
|
2024-07-20 18:21:29 +02:00
|
|
|
boost::asio::ssl::context m_context;
|
2024-07-05 23:54:18 +02:00
|
|
|
};
|
|
|
|
|
|
2024-07-23 20:02:14 +02:00
|
|
|
class NetworkManagerSSLSocketProxy : public NetworkManagerSocketProxyBase
|
|
|
|
|
{
|
|
|
|
|
public:
|
2024-08-13 22:52:15 +02:00
|
|
|
NetworkManagerSSLSocketProxy(boost::asio::ssl::stream<tcp::socket> socket);
|
2025-02-08 19:05:26 +01:00
|
|
|
NetworkManagerSSLSocketProxy(boost::asio::io_context &ioContext);
|
2024-08-21 16:53:34 +02:00
|
|
|
|
|
|
|
|
void setClientCertificate(const Streaming::ConstBuffer &data);
|
2024-07-23 20:02:14 +02:00
|
|
|
|
|
|
|
|
tcp::endpoint remote_endpoint() const override;
|
2024-08-21 16:53:34 +02:00
|
|
|
void newConnection(const tcp::endpoint &to, const std::shared_ptr<NetworkManagerConnection> &owner,
|
|
|
|
|
const std::function<void (const boost::system::error_code &e)> &callback) override;
|
2024-07-23 20:02:14 +02:00
|
|
|
void async_write(const std::vector<Streaming::ConstBuffer> &data,
|
|
|
|
|
const std::function<void (const boost::system::error_code &e, std::size_t)> &callback) override;
|
|
|
|
|
void async_receive(Streaming::BufferPool &pool,
|
|
|
|
|
const std::function<void (const boost::system::error_code &e, std::size_t bytesReceived)> &callback) override;
|
|
|
|
|
bool is_open() const override;
|
|
|
|
|
void close() override;
|
2024-08-21 17:58:45 +02:00
|
|
|
bool isEncrypted() const override {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-07-23 20:02:14 +02:00
|
|
|
|
2024-08-13 22:52:15 +02:00
|
|
|
void doASyncHandshake(const std::shared_ptr<NetworkManagerConnection> &owner);
|
|
|
|
|
|
2024-07-23 20:02:14 +02:00
|
|
|
private:
|
2024-08-21 16:53:34 +02:00
|
|
|
// for outgoing connections we might need to make a new socket
|
|
|
|
|
// we need the context for that.
|
|
|
|
|
boost::asio::ssl::context m_context;
|
|
|
|
|
|
|
|
|
|
// the socket we work on.
|
2024-08-13 22:52:15 +02:00
|
|
|
boost::asio::ssl::stream<tcp::socket> m_socket;
|
2024-07-23 20:02:14 +02:00
|
|
|
};
|
2025-02-11 20:16:32 +01:00
|
|
|
#endif
|
2024-07-23 20:02:14 +02:00
|
|
|
|
2024-07-05 23:54:18 +02:00
|
|
|
class NetworkManagerServerSimple : public NetworkManagerServerBase
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
NetworkManagerServerSimple(const std::shared_ptr<NetworkManagerPrivate> &parent, tcp::endpoint endpoint, const std::function<void(NetworkConnection&)> &callback);
|
|
|
|
|
|
|
|
|
|
void shutdown() override;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void setupCallback() override;
|
2024-08-13 22:52:15 +02:00
|
|
|
std::shared_ptr<NetworkManagerConnection> createNewConnection(int connectionId, boost::asio::ip::tcp::socket && socket) override;
|
2024-07-05 23:54:18 +02:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
tcp::socket m_socket;
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-23 20:02:14 +02:00
|
|
|
class NetworkManagerBasicSocketProxy : public NetworkManagerSocketProxyBase
|
|
|
|
|
{
|
|
|
|
|
public:
|
2025-02-08 19:05:26 +01:00
|
|
|
NetworkManagerBasicSocketProxy(boost::asio::io_context &io_context);
|
2024-07-23 20:02:14 +02:00
|
|
|
NetworkManagerBasicSocketProxy(tcp::socket && socket);
|
|
|
|
|
|
|
|
|
|
tcp::endpoint remote_endpoint() const override;
|
2024-08-21 16:53:34 +02:00
|
|
|
void newConnection(const tcp::endpoint &to, const std::shared_ptr<NetworkManagerConnection> &owner,
|
2024-07-23 20:02:14 +02:00
|
|
|
const std::function<void (const boost::system::error_code &e)> &callback) override;
|
|
|
|
|
void async_write(const std::vector<Streaming::ConstBuffer> &data,
|
|
|
|
|
const std::function<void (const boost::system::error_code &e, std::size_t)> &callback) override;
|
|
|
|
|
void async_receive(Streaming::BufferPool &pool,
|
|
|
|
|
const std::function<void (const boost::system::error_code &e, std::size_t bytesReceived)> &callback) override;
|
|
|
|
|
bool is_open() const override;
|
|
|
|
|
void close() override;
|
2024-08-21 17:58:45 +02:00
|
|
|
bool isEncrypted() const override {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-07-23 20:02:14 +02:00
|
|
|
private:
|
|
|
|
|
tcp::socket m_socket;
|
|
|
|
|
};
|
2016-08-16 16:51:22 +02:00
|
|
|
|
|
|
|
|
struct BannedNode
|
|
|
|
|
{
|
|
|
|
|
EndPoint endPoint;
|
|
|
|
|
boost::posix_time::ptime banTimeout;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class NetworkManagerPrivate
|
|
|
|
|
{
|
|
|
|
|
public:
|
2025-02-08 19:05:26 +01:00
|
|
|
NetworkManagerPrivate(boost::asio::io_context &context);
|
2016-08-16 16:51:22 +02:00
|
|
|
~NetworkManagerPrivate();
|
|
|
|
|
|
2019-08-24 17:19:07 +02:00
|
|
|
inline void alwaysConnectingNewConnectionHandler(NetworkConnection &con) {
|
|
|
|
|
con.accept();
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-05 23:54:18 +02:00
|
|
|
enum ListenType {
|
|
|
|
|
PlainSocket,
|
|
|
|
|
SSLSocket
|
|
|
|
|
};
|
2024-07-20 18:21:29 +02:00
|
|
|
NetworkManagerServerBase *bind(ListenType type,
|
2024-07-05 23:54:18 +02:00
|
|
|
std::shared_ptr<NetworkManagerPrivate> me,
|
|
|
|
|
const boost::asio::ip::tcp::endpoint &endpoint, const std::function<void(NetworkConnection&)> &callback);
|
|
|
|
|
|
2016-08-16 16:51:22 +02:00
|
|
|
void punishNode(int connectionId, int punishScore);
|
|
|
|
|
void cronHourly(const boost::system::error_code& error);
|
|
|
|
|
|
2025-02-11 16:46:21 +01:00
|
|
|
boost::asio::io_context& ioContext;
|
2016-08-16 16:51:22 +02:00
|
|
|
|
|
|
|
|
std::map<int, std::shared_ptr<NetworkManagerConnection> > connections;
|
2020-05-10 00:46:41 +02:00
|
|
|
std::deque<std::shared_ptr<NetworkManagerConnection> > unusedConnections;
|
2016-08-16 16:51:22 +02:00
|
|
|
int lastConnectionId;
|
|
|
|
|
|
2020-05-10 22:40:24 +02:00
|
|
|
std::recursive_mutex mutex; // to lock access to things like the connections map
|
|
|
|
|
std::mutex connectionMutex;
|
2016-08-16 16:51:22 +02:00
|
|
|
bool isClosingDown;
|
|
|
|
|
|
2024-07-05 23:54:18 +02:00
|
|
|
std::vector<NetworkManagerServerBase *> servers;
|
2016-08-16 16:51:22 +02:00
|
|
|
|
|
|
|
|
std::list<BannedNode> banned;
|
2019-04-09 17:24:38 +02:00
|
|
|
std::list<NetworkServiceBase*> services;
|
2025-10-17 22:13:32 +02:00
|
|
|
boost::asio::system_timer m_cronHourly;
|
2020-03-26 19:28:24 +01:00
|
|
|
|
|
|
|
|
// support for the p2p legacy envelope design
|
|
|
|
|
uint8_t networkId[4] = { 0xE3, 0xE1, 0xF3, 0xE8};
|
|
|
|
|
std::map<int, std::string> messageIds;
|
|
|
|
|
std::map<std::string, int> messageIdsReverse;
|
2026-05-19 18:34:36 +02:00
|
|
|
|
|
|
|
|
size_t m_maxIncomingMessageSize;
|
2016-08-16 16:51:22 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#endif
|