feat(Core): replace ACE network with Boost.Asio (#6574)

This commit is contained in:
Kargatum
2021-07-16 15:43:56 +07:00
committed by GitHub
parent 7449496bb5
commit 8568c4fb33
64 changed files with 3242 additions and 4712 deletions

View File

@@ -28,4 +28,6 @@ void Acore::Banner::Show(char const* applicationName, void(*log)(char const* tex
{
logExtraInfo();
}
log(" ");
}

View File

@@ -52,7 +52,6 @@ target_link_libraries(common
PRIVATE
acore-core-interface
PUBLIC
ace
boost
argon2
g3dlib

View File

@@ -14,13 +14,12 @@
#include <utility>
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
#include <ace/config-all.h>
#include <ws2tcpip.h>
#if AC_COMPILER == AC_COMPILER_INTEL
# if !defined(BOOST_ASIO_HAS_MOVE)
# define BOOST_ASIO_HAS_MOVE
# endif // !defined(BOOST_ASIO_HAS_MOVE)
# endif // if WARHEAD_COMPILER == WARHEAD_COMPILER_INTEL
# endif // if AC_COMPILER == AC_COMPILER_INTEL
#else
#include <cstdlib>
#include <netdb.h>

View File

@@ -16,12 +16,12 @@
#define ACORE_BIGENDIAN 1
#if !defined(ACORE_ENDIAN)
# if defined (ACE_BIG_ENDIAN)
# if defined (BOOST_BIG_ENDIAN)
# define ACORE_ENDIAN ACORE_BIGENDIAN
# else //ACE_BYTE_ORDER != ACE_BIG_ENDIAN
# else
# define ACORE_ENDIAN ACORE_LITTLEENDIAN
# endif //ACE_BYTE_ORDER
#endif //ACORE_ENDIAN
# endif
#endif
#if AC_PLATFORM == AC_PLATFORM_WINDOWS
# define ACORE_PATH_MAX MAX_PATH

View File

@@ -12,11 +12,6 @@
#include <windows.h>
#include <winsvc.h>
// stupid ACE define
#ifdef main
#undef main
#endif //main
#if !defined(WINADVAPI)
#if !defined(_ADVAPI32_)
#define WINADVAPI DECLSPEC_IMPORT

View File

@@ -0,0 +1,154 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
*/
#ifndef MPSCQueue_h__
#define MPSCQueue_h__
#include <atomic>
#include <utility>
namespace Acore::Impl
{
// C++ implementation of Dmitry Vyukov's lock free MPSC queue
// http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue
template<typename T>
class MPSCQueueNonIntrusive
{
public:
MPSCQueueNonIntrusive() : _head(new Node()), _tail(_head.load(std::memory_order_relaxed))
{
Node* front = _head.load(std::memory_order_relaxed);
front->Next.store(nullptr, std::memory_order_relaxed);
}
~MPSCQueueNonIntrusive()
{
T* output;
while (Dequeue(output))
delete output;
Node* front = _head.load(std::memory_order_relaxed);
delete front;
}
void Enqueue(T* input)
{
Node* node = new Node(input);
Node* prevHead = _head.exchange(node, std::memory_order_acq_rel);
prevHead->Next.store(node, std::memory_order_release);
}
bool Dequeue(T*& result)
{
Node* tail = _tail.load(std::memory_order_relaxed);
Node* next = tail->Next.load(std::memory_order_acquire);
if (!next)
return false;
result = next->Data;
_tail.store(next, std::memory_order_release);
delete tail;
return true;
}
private:
struct Node
{
Node() = default;
explicit Node(T* data) : Data(data)
{
Next.store(nullptr, std::memory_order_relaxed);
}
T* Data;
std::atomic<Node*> Next;
};
std::atomic<Node*> _head;
std::atomic<Node*> _tail;
MPSCQueueNonIntrusive(MPSCQueueNonIntrusive const&) = delete;
MPSCQueueNonIntrusive& operator=(MPSCQueueNonIntrusive const&) = delete;
};
// C++ implementation of Dmitry Vyukov's lock free MPSC queue
// http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue
template<typename T, std::atomic<T*> T::* IntrusiveLink>
class MPSCQueueIntrusive
{
public:
MPSCQueueIntrusive() : _dummyPtr(reinterpret_cast<T*>(std::addressof(_dummy))), _head(_dummyPtr), _tail(_dummyPtr)
{
// _dummy is constructed from aligned_storage and is intentionally left uninitialized (it might not be default constructible)
// so we init only its IntrusiveLink here
std::atomic<T*>* dummyNext = new (&(_dummyPtr->*IntrusiveLink)) std::atomic<T*>();
dummyNext->store(nullptr, std::memory_order_relaxed);
}
~MPSCQueueIntrusive()
{
T* output;
while (Dequeue(output))
delete output;
}
void Enqueue(T* input)
{
(input->*IntrusiveLink).store(nullptr, std::memory_order_release);
T* prevHead = _head.exchange(input, std::memory_order_acq_rel);
(prevHead->*IntrusiveLink).store(input, std::memory_order_release);
}
bool Dequeue(T*& result)
{
T* tail = _tail.load(std::memory_order_relaxed);
T* next = (tail->*IntrusiveLink).load(std::memory_order_acquire);
if (tail == _dummyPtr)
{
if (!next)
return false;
_tail.store(next, std::memory_order_release);
tail = next;
next = (next->*IntrusiveLink).load(std::memory_order_acquire);
}
if (next)
{
_tail.store(next, std::memory_order_release);
result = tail;
return true;
}
T* head = _head.load(std::memory_order_acquire);
if (tail != head)
return false;
Enqueue(_dummyPtr);
next = (tail->*IntrusiveLink).load(std::memory_order_acquire);
if (next)
{
_tail.store(next, std::memory_order_release);
result = tail;
return true;
}
return false;
}
private:
std::aligned_storage_t<sizeof(T), alignof(T)> _dummy;
T* _dummyPtr;
std::atomic<T*> _head;
std::atomic<T*> _tail;
MPSCQueueIntrusive(MPSCQueueIntrusive const&) = delete;
MPSCQueueIntrusive& operator=(MPSCQueueIntrusive const&) = delete;
};
}
template<typename T, std::atomic<T*> T::* IntrusiveLink = nullptr>
using MPSCQueue = std::conditional_t<IntrusiveLink != nullptr, Acore::Impl::MPSCQueueIntrusive<T, IntrusiveLink>, Acore::Impl::MPSCQueueNonIntrusive<T>>;
#endif // MPSCQueue_h__

View File

@@ -100,7 +100,7 @@ private:
typename std::enable_if<std::is_pointer<E>::value>::type DeleteQueuedObject(E& obj) { delete obj; }
template<typename E = T>
typename std::enable_if < !std::is_pointer<E>::value >::type DeleteQueuedObject(E const& /*packet*/) { }
typename std::enable_if<!std::is_pointer<E>::value>::type DeleteQueuedObject(E const& /*packet*/) { }
};
#endif

View File

@@ -1,100 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
*/
#ifndef _PCQ_H
#define _PCQ_H
#include <condition_variable>
#include <mutex>
#include <queue>
#include <atomic>
#include <type_traits>
template <typename T>
class ProducerConsumerQueue
{
private:
std::mutex _queueLock;
std::queue<T> _queue;
std::condition_variable _condition;
std::atomic<bool> _shutdown;
public:
ProducerConsumerQueue<T>() : _shutdown(false) { }
void Push(const T& value)
{
std::lock_guard<std::mutex> lock(_queueLock);
_queue.push(std::move(value));
_condition.notify_one();
}
bool Empty()
{
std::lock_guard<std::mutex> lock(_queueLock);
return _queue.empty();
}
bool Pop(T& value)
{
std::lock_guard<std::mutex> lock(_queueLock);
if (_queue.empty() || _shutdown)
return false;
value = _queue.front();
_queue.pop();
return true;
}
void WaitAndPop(T& value)
{
std::unique_lock<std::mutex> lock(_queueLock);
// we could be using .wait(lock, predicate) overload here but it is broken
// https://connect.microsoft.com/VisualStudio/feedback/details/1098841
while (_queue.empty() && !_shutdown)
_condition.wait(lock);
if (_queue.empty() || _shutdown)
return;
value = _queue.front();
_queue.pop();
}
void Cancel()
{
std::unique_lock<std::mutex> lock(_queueLock);
while (!_queue.empty())
{
T& value = _queue.front();
DeleteQueuedObject(value);
_queue.pop();
}
_shutdown = true;
_condition.notify_all();
}
private:
template<typename E = T>
typename std::enable_if<std::is_pointer<E>::value>::type DeleteQueuedObject(E& obj) { delete obj; }
template<typename E = T>
typename std::enable_if<!std::is_pointer<E>::value>::type DeleteQueuedObject(E const& /*packet*/) { }
};
#endif

View File

@@ -7,9 +7,9 @@
#include "Util.h"
#include "Common.h"
#include "Containers.h"
#include "IpAddress.h"
#include "StringConvert.h"
#include "StringFormat.h"
#include <ace/Default_Constants.h>
#include <algorithm>
#include <cctype>
#include <cstdarg>
@@ -17,8 +17,10 @@
#include <iomanip>
#include <sstream>
#include <string>
#include <cctype>
#include <cstdarg>
#include <ctime>
#include <utf8.h>
// #include "IpAddress.h"
Tokenizer::Tokenizer(const std::string& src, const char sep, uint32 vectorReserve)
{
@@ -295,26 +297,9 @@ bool IsIPAddress(char const* ipaddress)
return false;
}
// Let the big boys do it.
// Drawback: all valid ip address formats are recognized e.g.: 12.23, 121234, 0xABCD)
return inet_addr(ipaddress) != INADDR_NONE;
}
std::string GetAddressString(ACE_INET_Addr const& addr)
{
char buf[ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16];
addr.addr_to_string(buf, ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16);
return buf;
}
bool IsIPAddrInNetwork(ACE_INET_Addr const& net, ACE_INET_Addr const& addr, ACE_INET_Addr const& subnetMask)
{
uint32 mask = subnetMask.get_ip_address();
if ((net.get_ip_address() & mask) == (addr.get_ip_address() & mask))
{
return true;
}
return false;
boost::system::error_code error;
Acore::Net::make_address(ipaddress, error);
return !error;
}
/// create PID file

View File

@@ -10,7 +10,6 @@
#include "Containers.h"
#include "Define.h"
#include "Errors.h"
#include <ace/INET_Addr.h>
#include <algorithm>
#include <array>
#include <cctype>
@@ -18,6 +17,9 @@
#include <map>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <array>
// Searcher for map of structs
template<typename T, class S> struct Finder
@@ -383,12 +385,6 @@ bool Utf8ToUpperOnlyLatin(std::string& utf8String);
bool IsIPAddress(char const* ipaddress);
/// Checks if address belongs to the a network with specified submask
bool IsIPAddrInNetwork(ACE_INET_Addr const& net, ACE_INET_Addr const& addr, ACE_INET_Addr const& subnetMask);
/// Transforms ACE_INET_Addr address into string format "dotted_ip:port"
std::string GetAddressString(ACE_INET_Addr const& addr);
uint32 CreatePIDFile(const std::string& filename);
uint32 GetPID();