Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 203 additions & 0 deletions core/include/join/protocol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ namespace join
template <class Protocol>
class BasicTlsAcceptor;

template <class Protocol>
class BasicDatagramResolver;
template <class Protocol>
class BasicTlsResolver;

template <class Protocol>
class BasicHttpClient;
template <class Protocol>
Expand Down Expand Up @@ -671,6 +676,204 @@ namespace join
return !(a == b);
}

/**
* @brief DNS over UDP protocol class.
*/
class Dns
{
public:
using Endpoint = BasicInternetEndpoint<Dns>;
using Socket = BasicDatagramSocket<Dns>;
using Resolver = BasicDatagramResolver<Dns>;

/**
* @brief construct the DNS protocol instance.
* @param family IP address family.
*/
constexpr Dns (int family = AF_INET) noexcept
: _family (family)
{
}

/**
* @brief get protocol suitable for IPv4 address family.
* @return an IPv4 address family suitable protocol.
*/
static inline Dns& v4 () noexcept
{
static Dns dnsv4 (AF_INET);
return dnsv4;
}

/**
* @brief get protocol suitable for IPv6 address family.
* @return an IPv6 address family suitable protocol.
*/
static inline Dns& v6 () noexcept
{
static Dns dnsv6 (AF_INET6);
return dnsv6;
}

/**
* @brief get the protocol IP address family.
* @return the protocol IP address family.
*/
constexpr int family () const noexcept
{
return _family;
}

/**
* @brief get the protocol communication semantic.
* @return the protocol communication semantic.
*/
constexpr int type () const noexcept
{
return SOCK_DGRAM;
}

/**
* @brief get the protocol type.
* @return the protocol type.
*/
constexpr int protocol () const noexcept
{
return IPPROTO_UDP;
}

/// default DNS port.
static constexpr uint16_t defaultPort = 53;

/// maximum DNS message size.
static constexpr size_t maxMsgSize = 8192;

private:
/// IP address family.
int _family;
};

/**
* @brief check if equals.
* @param a protocol to check.
* @param b protocol to check.
* @return true if equals.
*/
constexpr bool operator== (const Dns& a, const Dns& b) noexcept
{
return a.family () == b.family ();
}

/**
* @brief check if not equals.
* @param a protocol to check.
* @param b protocol to check.
* @return true if not equals.
*/
constexpr bool operator!= (const Dns& a, const Dns& b) noexcept
{
return !(a == b);
}

/**
* @brief DNS over TLS protocol class.
*/
class Dot
{
public:
using Endpoint = BasicInternetEndpoint<Dot>;
using Socket = BasicTlsSocket<Dot>;
using Resolver = BasicTlsResolver<Dot>;

/**
* @brief construct the DoT protocol instance.
* @param family IP address family.
*/
constexpr Dot (int family = AF_INET) noexcept
: _family (family)
{
}

/**
* @brief get protocol suitable for IPv4 address family.
* @return an IPv4 address family suitable protocol.
*/
static inline Dot& v4 () noexcept
{
static Dot dotv4 (AF_INET);
return dotv4;
}

/**
* @brief get protocol suitable for IPv6 address family.
* @return an IPv6 address family suitable protocol.
*/
static inline Dot& v6 () noexcept
{
static Dot dotv6 (AF_INET6);
return dotv6;
}

/**
* @brief get the protocol IP address family.
* @return the protocol IP address family.
*/
constexpr int family () const noexcept
{
return _family;
}

/**
* @brief get the protocol communication semantic.
* @return the protocol communication semantic.
*/
constexpr int type () const noexcept
{
return SOCK_STREAM;
}

/**
* @brief get the protocol type.
* @return the protocol type.
*/
constexpr int protocol () const noexcept
{
return IPPROTO_TCP;
}

/// default DoT port.
static constexpr uint16_t defaultPort = 853;

/// maximum DoT message size.
static constexpr size_t maxMsgSize = 16384;

private:
/// IP address family.
int _family;
};

/**
* @brief check if equals.
* @param a protocol to check.
* @param b protocol to check.
* @return true if equals.
*/
constexpr bool operator== (const Dot& a, const Dot& b) noexcept
{
return a.family () == b.family ();
}

/**
* @brief check if not equals.
* @param a protocol to check.
* @param b protocol to check.
* @return true if not equals.
*/
constexpr bool operator!= (const Dot& a, const Dot& b) noexcept
{
return !(a == b);
}

/**
* @brief HTTP protocol class.
*/
Expand Down
47 changes: 38 additions & 9 deletions core/include/join/socket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ namespace join
* @brief determine the local endpoint associated with this socket.
* @return local endpoint.
*/
Endpoint localEndpoint () const
Endpoint localEndpoint () const noexcept
{
struct sockaddr_storage sa;
socklen_t sa_len = sizeof (struct sockaddr_storage);
Expand Down Expand Up @@ -590,7 +590,7 @@ namespace join
handle.events |= POLLOUT;
}

int nset = (handle.fd > -1) ? ::poll (&handle, 1, timeout) : -1;
int nset = (handle.fd > -1) ? ::poll (&handle, 1, timeout == 0 ? -1 : timeout) : -1;
if (nset != 1)
{
if (nset == -1)
Expand Down Expand Up @@ -1053,7 +1053,7 @@ namespace join
* @brief determine the remote endpoint associated with this socket.
* @return remote endpoint.
*/
const Endpoint& remoteEndpoint () const
const Endpoint& remoteEndpoint () const noexcept
{
return this->_remote;
}
Expand Down Expand Up @@ -1109,7 +1109,7 @@ namespace join
* @brief returns the Time-To-Live value.
* @return The Time-To-Live value.
*/
int ttl () const
int ttl () const noexcept
{
return this->_ttl;
}
Expand Down Expand Up @@ -1691,16 +1691,19 @@ namespace join
* @param endpoint endpoint to connect to.
* @return 0 on success, -1 on failure.
*/
int connectEncrypted (const Endpoint& endpoint)
virtual int connectEncrypted (const Endpoint& endpoint)
{
if (BasicStreamSocket<Protocol>::connect (endpoint) == -1)
if (this->connect (endpoint) == -1)
{
return -1;
}

if (this->startEncryption () == -1)
{
this->close ();
if (lastError != Errc::TemporaryError)
{
this->close ();
}
return -1;
}

Expand Down Expand Up @@ -1763,7 +1766,7 @@ namespace join
* @param timeout timeout in milliseconds (0: infinite).
* return true on success, false otherwise.
*/
bool waitEncrypted (int timeout = 0)
virtual bool waitEncrypted (int timeout = 0)
{
if (this->encrypted () == false)
{
Expand Down Expand Up @@ -2144,7 +2147,7 @@ namespace join
* @param verify Enable peer verification if set to true, false otherwise.
* @param depth The maximum certificate verification depth (default: no limit).
*/
void setVerify (bool verify, int depth = -1)
void setVerify (bool verify, int depth = -1) noexcept
{
if (verify == true)
{
Expand Down Expand Up @@ -2191,6 +2194,32 @@ namespace join
return 0;
}

/**
* @brief set the ALPN protocols list.
* @param protocols list of protocol names (ex. {"h2", "http/1.1"}).
* @return 0 on success, -1 on failure.
*/
int setAlpnProtocols (const std::vector<std::string>& protocols)
{
std::vector<uint8_t> wire;
wire.reserve (256);

for (auto const& proto : protocols)
{
wire.push_back (static_cast<uint8_t> (proto.size ()));
wire.insert (wire.end (), proto.begin (), proto.end ());
}

if (SSL_CTX_set_alpn_protos (this->_tlsContext.get (), wire.data (),
static_cast<unsigned int> (wire.size ())) != 0)
{
lastError = make_error_code (Errc::InvalidParam);
return -1;
}

return 0;
}

protected:
/**
* @brief TLS state.
Expand Down
22 changes: 22 additions & 0 deletions core/tests/protocol_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ using join::Udp;
using join::Icmp;
using join::Tcp;
using join::Tls;
using join::Dns;
using join::Dot;
using join::Http;
using join::Https;
using join::Smtp;
Expand All @@ -61,6 +63,12 @@ TEST (Protocol, family)
ASSERT_EQ (Tls ().family (), AF_INET);
ASSERT_EQ (Tls::v6 ().family (), AF_INET6);
ASSERT_EQ (Tls::v4 ().family (), AF_INET);
ASSERT_EQ (Dns ().family (), AF_INET);
ASSERT_EQ (Dns::v6 ().family (), AF_INET6);
ASSERT_EQ (Dns::v4 ().family (), AF_INET);
ASSERT_EQ (Dot ().family (), AF_INET);
ASSERT_EQ (Dot::v6 ().family (), AF_INET6);
ASSERT_EQ (Dot::v4 ().family (), AF_INET);
ASSERT_EQ (Http ().family (), AF_INET);
ASSERT_EQ (Http::v6 ().family (), AF_INET6);
ASSERT_EQ (Http::v4 ().family (), AF_INET);
Expand Down Expand Up @@ -88,6 +96,8 @@ TEST (Protocol, type)
ASSERT_EQ (Icmp ().type (), SOCK_RAW);
ASSERT_EQ (Tcp ().type (), SOCK_STREAM);
ASSERT_EQ (Tls ().type (), SOCK_STREAM);
ASSERT_EQ (Dns ().type (), SOCK_DGRAM);
ASSERT_EQ (Dot ().type (), SOCK_STREAM);
ASSERT_EQ (Http ().type (), SOCK_STREAM);
ASSERT_EQ (Https ().type (), SOCK_STREAM);
ASSERT_EQ (Smtp ().type (), SOCK_STREAM);
Expand All @@ -108,6 +118,8 @@ TEST (Protocol, protocol)
ASSERT_EQ (Icmp::v4 ().protocol (), IPPROTO_ICMP);
ASSERT_EQ (Tcp ().protocol (), IPPROTO_TCP);
ASSERT_EQ (Tls ().protocol (), IPPROTO_TCP);
ASSERT_EQ (Dns ().protocol (), IPPROTO_UDP);
ASSERT_EQ (Dot ().protocol (), IPPROTO_TCP);
ASSERT_EQ (Http ().protocol (), IPPROTO_TCP);
ASSERT_EQ (Https ().protocol (), IPPROTO_TCP);
ASSERT_EQ (Smtp ().protocol (), IPPROTO_TCP);
Expand Down Expand Up @@ -142,6 +154,16 @@ TEST (Protocol, equal)
ASSERT_EQ (Tls::v6 (), Tls::v6 ());
ASSERT_NE (Tls::v6 (), Tls::v4 ());

ASSERT_EQ (Dns::v4 (), Dns::v4 ());
ASSERT_NE (Dns::v4 (), Dns::v6 ());
ASSERT_EQ (Dns::v6 (), Dns::v6 ());
ASSERT_NE (Dns::v6 (), Dns::v4 ());

ASSERT_EQ (Dot::v4 (), Dot::v4 ());
ASSERT_NE (Dot::v4 (), Dot::v6 ());
ASSERT_EQ (Dot::v6 (), Dot::v6 ());
ASSERT_NE (Dot::v6 (), Dot::v4 ());

ASSERT_EQ (Http::v4 (), Http::v4 ());
ASSERT_NE (Http::v4 (), Http::v6 ());
ASSERT_EQ (Http::v6 (), Http::v6 ());
Expand Down
Loading