#pragma once
#include <chrono>
#include <cstdint>
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#include <system_error>
#include <boost/asio.hpp>
#include "go_handle.hpp"
#if __INTELLISENSE__
#define UNIX_DGRAM_AVAILABLE
#define UNIX_STREAM_AVAILABLE
#else
#ifdef _WIN32
#define UNIX_STREAM_AVAILABLE
#else
#define UNIX_DGRAM_AVAILABLE
#define UNIX_STREAM_AVAILABLE
#endif
#endif
#ifdef _WIN32
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif
namespace Pan {
enum class Error
{
Ok = 0,
Failed = 1,
Deadline = 2,
NoPath = 3,
AddrSyntax = 4,
AddrResolution = 5
};
class Exception : public virtual std::exception
{
public:
DLLEXPORT
Exception(std::uint32_t error);
const std::error_code& code() const noexcept
{ return ec; }
const char* what() const noexcept override
{ return message->c_str(); }
private:
std::error_code ec;
std::shared_ptr<std::string> message;
};
typedef std::uint64_t IA;
namespace udp {
class Endpoint;
}
class PathInterface final
{
public:
explicit PathInterface(GoHandle&& handle)
: h(std::move(handle))
{}
operator bool() const noexcept { return h.isValid(); }
bool isValid() const noexcept { return h.isValid(); }
std::uintptr_t getHandle() const noexcept { return h.get(); }
std::uintptr_t releaseHandle() noexcept { return h.release(); }
private:
GoHandle h;
};
class PathFingerprint final
{
public:
PathFingerprint();
explicit PathFingerprint(GoHandle&& handle)
: h(std::move(handle))
{}
operator bool() const noexcept { return h.isValid(); }
bool isValid() const noexcept { return h.isValid(); }
std::uintptr_t getHandle() const noexcept { return h.get(); }
std::uintptr_t releaseHandle() noexcept { return h.release(); }
DLLEXPORT
bool operator==(const PathFingerprint &other) const noexcept;
DLLEXPORT
bool operator!=(const PathFingerprint &other) const noexcept;
private:
GoHandle h;
};
class Path final
{
public:
Path() = default;
explicit Path(GoHandle&& handle)
: h(std::move(handle))
{}
operator bool() const noexcept { return h.isValid(); }
bool isValid() const noexcept { return h.isValid(); }
std::uintptr_t getHandle() const noexcept { return h.get(); }
std::uintptr_t releaseHandle() noexcept { return h.release(); }
DLLEXPORT
std::string toString() const;
DLLEXPORT
PathFingerprint getFingerprint() const;
DLLEXPORT
bool containsInterface(const PathInterface &iface) const;
private:
GoHandle h;
};
class PathPolicy
{
public:
DLLEXPORT
PathPolicy();
virtual ~PathPolicy(){}
operator bool() const noexcept { return h.isValid(); }
bool isValid() const noexcept { return h.isValid(); }
std::uintptr_t getHandle() const noexcept { return h.get(); }
std::uintptr_t releaseHandle() noexcept { return h.release(); }
public:
static std::size_t cbFilter(std::uintptr_t* paths, std::size_t count, std::uintptr_t user);
protected:
using PathTag = std::uintptr_t;
using Paths = std::vector<std::pair<Path, PathTag>>;
virtual void filter(Paths& paths) = 0;
private:
GoHandle h;
};
class PathSelector
{
public:
DLLEXPORT
PathSelector();
virtual ~PathSelector(){}
operator bool() const noexcept { return h.isValid(); }
bool isValid() const noexcept { return h.isValid(); }
std::uintptr_t getHandle() const noexcept { return h.get(); }
std::uintptr_t releaseHandle() noexcept { return h.release(); }
public:
static std::uintptr_t cbPath(std::uintptr_t user);
static void cbInitialize(
std::uintptr_t local, std::uintptr_t remote,
std::uintptr_t* paths, size_t count, std::uintptr_t user);
static void cbRefresh(std::uintptr_t* paths, size_t count, std::uintptr_t user);
static void cbPathDown(std::uintptr_t pf, std::uintptr_t pi, uintptr_t user);
static void cbClose(std::uintptr_t user);
protected:
virtual Path path() = 0;
virtual void initialize(
udp::Endpoint local, udp::Endpoint remote, std::vector<Path>& paths) = 0;
virtual void refresh(std::vector<Path>& paths) = 0;
virtual void pathDown(PathFingerprint pf, PathInterface pi) = 0;
virtual void close() = 0;
private:
GoHandle h;
};
class ReplySelector
{
public:
DLLEXPORT
ReplySelector();
virtual ~ReplySelector(){}
operator bool() const noexcept { return h.isValid(); }
bool isValid() const noexcept { return h.isValid(); }
std::uintptr_t getHandle() const noexcept { return h.get(); }
std::uintptr_t releaseHandle() noexcept { return h.release(); }
public:
static std::uintptr_t cbPath(std::uintptr_t remote, std::uintptr_t user);
static void cbInitialize(std::uintptr_t local, std::uintptr_t user);
static void cbRecord(std::uintptr_t remote, std::uintptr_t path, std::uintptr_t user);
static void cbPathDown(std::uintptr_t pf, std::uintptr_t pi, std::uintptr_t user);
static void cbClose(std::uintptr_t user);
protected:
virtual Path path(udp::Endpoint remote) = 0;
virtual void initialize(udp::Endpoint local) = 0;
virtual void record(udp::Endpoint remote, Path path) = 0;
virtual void pathDown(PathFingerprint pf, PathInterface pi) = 0;
virtual void close() = 0;
private:
GoHandle h;
};
namespace udp {
using namespace boost;
class Endpoint final
{
public:
Endpoint() = default;
explicit Endpoint(GoHandle&& handle)
: h(std::move(handle))
{}
Endpoint(IA ia, const asio::ip::udp::endpoint& ep)
: Endpoint(ia, ep.address(), ep.port())
{}
DLLEXPORT
Endpoint(IA ia, const asio::ip::address& ip, std::uint16_t port);
operator bool() const noexcept { return h.isValid(); }
bool isValid() const noexcept { return h.isValid(); }
std::uintptr_t getHandle() const noexcept { return h.get(); }
std::uintptr_t releaseHandle() noexcept { return h.release(); }
DLLEXPORT
IA getIA() const;
DLLEXPORT
asio::ip::address getIP() const;
DLLEXPORT
std::uint16_t getPort() const;
DLLEXPORT
std::string toString() const;
friend std::ostream& operator<<(std::ostream& stream, const Endpoint& ep)
{
stream << ep.toString();
return stream;
}
private:
GoHandle h;
};
DLLEXPORT
Endpoint resolveUDPAddr(const char* address);
DLLEXPORT
Endpoint resolveUDPAddr(const char* address, std::error_code &ec) noexcept;
#ifdef UNIX_DGRAM_AVAILABLE
class ListenSockAdapter final
{
public:
ListenSockAdapter() = default;
ListenSockAdapter(const ListenSockAdapter& other) = delete;
ListenSockAdapter(ListenSockAdapter&& other) = default;
ListenSockAdapter& operator=(const ListenSockAdapter& other) = delete;
ListenSockAdapter& operator=(ListenSockAdapter&& other) = default;
~ListenSockAdapter() noexcept { close(); }
operator bool() const noexcept { return h.isValid(); }
bool isValid() const noexcept { return h.isValid(); }
std::uintptr_t getHandle() const noexcept { return h.get(); }
std::uintptr_t releaseHandle() noexcept { return h.release(); }
DLLEXPORT
void close() noexcept;
private:
ListenSockAdapter(GoHandle handle) noexcept;
friend class ListenConn;
private:
GoHandle h;
};
#endif
#ifdef UNIX_STREAM_AVAILABLE
class ListenSSockAdapter final
{
public:
ListenSSockAdapter() = default;
ListenSSockAdapter(const ListenSSockAdapter& other) = delete;
ListenSSockAdapter(ListenSSockAdapter&& other) = default;
ListenSSockAdapter& operator=(const ListenSSockAdapter& other) = delete;
ListenSSockAdapter& operator=(ListenSSockAdapter&& other) = default;
~ListenSSockAdapter() noexcept { close(); }
operator bool() const noexcept { return h.isValid(); }
bool isValid() const noexcept { return h.isValid(); }
std::uintptr_t getHandle() const noexcept { return h.get(); }
std::uintptr_t releaseHandle() noexcept { return h.release(); }
DLLEXPORT
void close() noexcept;
private:
DLLEXPORT
ListenSSockAdapter(GoHandle handle) noexcept;
friend class ListenConn;
private:
GoHandle h;
};
#endif
class ListenConn final
{
public:
DLLEXPORT
ListenConn(std::unique_ptr<ReplySelector> selector = nullptr) noexcept;
DLLEXPORT
ListenConn(const char* bind, std::unique_ptr<ReplySelector> selector);
DLLEXPORT
ListenConn(const char* bind, std::unique_ptr<ReplySelector> selector, std::error_code &ec) noexcept;
ListenConn(const ListenConn& other) = delete;
ListenConn(ListenConn&& other) = default;
ListenConn& operator=(const ListenConn& other) = delete;
ListenConn& operator=(ListenConn&& other) = default;
~ListenConn() noexcept { close(); }
operator bool() const noexcept { return h.isValid(); }
bool isValid() const noexcept { return h.isValid(); }
std::uintptr_t getHandle() const noexcept { return h.get(); }
std::uintptr_t releaseHandle() noexcept { return h.release(); }
DLLEXPORT
void listen(const char* bind);
DLLEXPORT
void listen(const char* bind, std::error_code &ec) noexcept;
DLLEXPORT
void close() noexcept;
DLLEXPORT
Endpoint getLocalEndpoint() const;
DLLEXPORT
void setDeadline(std::chrono::milliseconds t);
DLLEXPORT
void setReadDeadline(std::chrono::milliseconds t);
DLLEXPORT
void setWriteDeadline(std::chrono::milliseconds t);
DLLEXPORT
std::size_t readFrom(asio::mutable_buffer buffer, Endpoint* from);
DLLEXPORT
std::size_t readFrom(asio::mutable_buffer buffer, Endpoint* from, std::error_code& ec) noexcept;
DLLEXPORT
std::size_t readFromVia(asio::mutable_buffer buffer, Endpoint* from, Path* path);
DLLEXPORT
std::size_t readFromVia(asio::mutable_buffer buffer, Endpoint* from, Path* path, std::error_code& ec) noexcept;
DLLEXPORT
std::size_t writeTo(asio::const_buffer buffer, const Endpoint& to);
DLLEXPORT
std::size_t writeTo(asio::const_buffer buffer, const Endpoint& to, std::error_code& ec) noexcept;
DLLEXPORT
std::size_t writeToVia(asio::const_buffer buffer, const Endpoint& to, const Path& path);
DLLEXPORT
std::size_t writeToVia(asio::const_buffer buffer, const Endpoint& to, const Path& path, std::error_code& ec) noexcept;
#ifdef UNIX_DGRAM_AVAILABLE
DLLEXPORT
ListenSockAdapter createSockAdapter(const char* goSocketPath, const char* cSocketPath);
ListenSockAdapter createSockAdapter(const char* goSocketPath, const char* cSocketPath, std::error_code &ec) noexcept;
#endif
#ifdef UNIX_STREAM_AVAILABLE
DLLEXPORT
ListenSSockAdapter createSSockAdapter(const char* goSocketPath);
DLLEXPORT
ListenSSockAdapter createSSockAdapter(const char* goSocketPath, std::error_code &ec) noexcept;
#endif
private:
GoHandle h;
std::unique_ptr<ReplySelector> selector;
};
#ifdef UNIX_DGRAM_AVAILABLE
class ConnSockAdapter
{
public:
ConnSockAdapter() = default;
ConnSockAdapter(const ConnSockAdapter& other) = delete;
ConnSockAdapter(ConnSockAdapter&& other) = default;
ConnSockAdapter& operator=(const ConnSockAdapter& other) = delete;
ConnSockAdapter& operator=(ConnSockAdapter&& other) = default;
~ConnSockAdapter() noexcept { close(); }
operator bool() const noexcept { return h.isValid(); }
bool isValid() const noexcept { return h.isValid(); }
std::uintptr_t getHandle() const noexcept { return h.get(); }
std::uintptr_t releaseHandle() noexcept { return h.release(); }
DLLEXPORT
void close() noexcept;
private:
DLLEXPORT
ConnSockAdapter(GoHandle handle) noexcept;
friend class Conn;
private:
GoHandle h;
};
#endif
#ifdef UNIX_STREAM_AVAILABLE
class ConnSSockAdapter
{
public:
ConnSSockAdapter() = default;
ConnSSockAdapter(const ConnSSockAdapter& other) = delete;
ConnSSockAdapter(ConnSSockAdapter&& other) = default;
ConnSSockAdapter& operator=(const ConnSSockAdapter& other) = delete;
ConnSSockAdapter& operator=(ConnSSockAdapter&& other) = default;
~ConnSSockAdapter() noexcept { close(); }
operator bool() const noexcept { return h.isValid(); }
bool isValid() const noexcept { return h.isValid(); }
std::uintptr_t getHandle() const noexcept { return h.get(); }
std::uintptr_t releaseHandle() noexcept { return h.release(); }
DLLEXPORT
void close() noexcept;
private:
DLLEXPORT
ConnSSockAdapter(GoHandle handle) noexcept;
friend class Conn;
private:
GoHandle h;
};
#endif
class Conn final
{
public:
DLLEXPORT
Conn(std::unique_ptr<PathPolicy> policy = nullptr,
std::unique_ptr<PathSelector> selector = nullptr) noexcept;
DLLEXPORT
Conn(const char *local, const Endpoint& remote,
std::unique_ptr<PathPolicy> policy, std::unique_ptr<PathSelector> selector);
DLLEXPORT
Conn(const char *local, const Endpoint& remote,
std::unique_ptr<PathPolicy> policy, std::unique_ptr<PathSelector> selector,
std::error_code &ec) noexcept;
Conn(const Conn& other) = delete;
Conn(Conn&& other) = default;
Conn& operator=(const Conn& other) = delete;
Conn& operator=(Conn&& other) = default;
~Conn() noexcept { close(); }
operator bool() const noexcept { return h.isValid(); }
bool isValid() const noexcept { return h.isValid(); }
std::uintptr_t getHandle() const noexcept { return h.get(); }
std::uintptr_t releaseHandle() noexcept { return h.release(); }
DLLEXPORT
void dial(const char *local, const Endpoint& remote);
DLLEXPORT
void dial(const char *local, const Endpoint& remote, std::error_code &ec) noexcept;
DLLEXPORT
void close() noexcept;
DLLEXPORT
Endpoint getLocalEndpoint() const;
DLLEXPORT
Endpoint getRemoteEndpoint() const;
DLLEXPORT
void setDeadline(std::chrono::milliseconds t);
DLLEXPORT
void setReadDeadline(std::chrono::milliseconds t);
DLLEXPORT
void setWriteDeadline(std::chrono::milliseconds t);
DLLEXPORT
std::size_t read(asio::mutable_buffer buffer);
DLLEXPORT
std::size_t read(asio::mutable_buffer buffer, std::error_code& ec) noexcept;
DLLEXPORT
std::size_t readVia(asio::mutable_buffer buffer, Path* path);
DLLEXPORT
std::size_t readVia(asio::mutable_buffer buffer, Path* path, std::error_code& ec) noexcept;
DLLEXPORT
std::size_t write(asio::const_buffer buffer);
DLLEXPORT
std::size_t write(asio::const_buffer buffer, std::error_code& ec) noexcept;
DLLEXPORT
std::size_t writeVia(asio::const_buffer buffer, const Path& path);
DLLEXPORT
std::size_t writeVia(asio::const_buffer buffer, const Path& path, std::error_code& ec) noexcept;
#ifdef UNIX_DGRAM_AVAILABLE
DLLEXPORT
ConnSockAdapter createSockAdapter(const char* goSocketPath, const char* cSocketPath);
DLLEXPORT
ConnSockAdapter createSockAdapter(const char* goSocketPath, const char* cSocketPath, std::error_code &ec) noexcept;
#endif
#ifdef UNIX_STREAM_AVAILABLE
DLLEXPORT
ConnSSockAdapter createSSockAdapter(const char* goSocketPath);
DLLEXPORT
ConnSSockAdapter createSSockAdapter(const char* goSocketPath, std::error_code &ec) noexcept;
#endif
private:
GoHandle h;
std::unique_ptr<PathPolicy> policy;
std::unique_ptr<PathSelector> selector;
};
} }
namespace std
{
template <>
struct is_error_code_enum<Pan::Error> : true_type {};
}