mirror of
https://github.com/matrix-construct/construct
synced 2024-11-29 02:02:38 +01:00
ircd::net: Refine socket interfaces; connection options structure.
This commit is contained in:
parent
0e1b605991
commit
7e0c01708a
4 changed files with 841 additions and 643 deletions
|
@ -37,12 +37,9 @@ namespace ircd::net
|
|||
IRCD_EXCEPTION(error, nxdomain)
|
||||
IRCD_EXCEPTION(error, broken_pipe)
|
||||
IRCD_EXCEPTION(error, disconnected)
|
||||
IRCD_EXCEPTION(error, inauthentic)
|
||||
|
||||
struct init;
|
||||
struct remote;
|
||||
struct socket;
|
||||
struct listener;
|
||||
enum class dc;
|
||||
|
||||
// SNOMASK 'N' "net"
|
||||
extern struct log::log log;
|
||||
|
@ -51,49 +48,10 @@ namespace ircd::net
|
|||
#include "remote.h"
|
||||
#include "resolve.h"
|
||||
#include "listener.h"
|
||||
|
||||
enum class ircd::net::dc
|
||||
{
|
||||
RST, ///< hardest immediate termination
|
||||
FIN, ///< sd graceful shutdown both directions
|
||||
FIN_SEND, ///< sd graceful shutdown send side
|
||||
FIN_RECV, ///< sd graceful shutdown recv side
|
||||
SSL_NOTIFY, ///< SSL close_notify (async, errors ignored)
|
||||
SSL_NOTIFY_YIELD, ///< SSL close_notify (yields context, throws)
|
||||
};
|
||||
|
||||
// Public interface to socket.h because it is not included here.
|
||||
namespace ircd::net
|
||||
{
|
||||
bool connected(const socket &) noexcept;
|
||||
size_t available(const socket &) noexcept;
|
||||
ipport local_ipport(const socket &) noexcept;
|
||||
ipport remote_ipport(const socket &) noexcept;
|
||||
|
||||
const_raw_buffer peer_cert_der(const mutable_raw_buffer &, const socket &);
|
||||
|
||||
size_t write(socket &, const ilist<const_buffer> &); // write_all
|
||||
size_t write(socket &, const iov<const_buffer> &); // write_all
|
||||
size_t write(socket &, iov<const_buffer> &); // write_some
|
||||
|
||||
size_t read(socket &, const ilist<mutable_buffer> &); // read_all
|
||||
size_t read(socket &, const iov<mutable_buffer> &); // read_all
|
||||
size_t read(socket &, iov<mutable_buffer> &); // read_some
|
||||
|
||||
std::shared_ptr<socket> connect(const remote &, const milliseconds &timeout = 30000ms);
|
||||
bool disconnect(socket &, const dc &type = dc::SSL_NOTIFY) noexcept;
|
||||
|
||||
ctx::future<std::shared_ptr<socket>> open(const ipport &, std::string cn, const milliseconds &timeout = 30000ms);
|
||||
ctx::future<std::shared_ptr<socket>> open(const hostport &, const milliseconds &timeout = 30000ms);
|
||||
}
|
||||
#include "sockpub.h"
|
||||
|
||||
struct ircd::net::init
|
||||
{
|
||||
init();
|
||||
~init() noexcept;
|
||||
};
|
||||
|
||||
namespace ircd
|
||||
{
|
||||
using net::socket;
|
||||
}
|
||||
|
|
|
@ -25,17 +25,14 @@
|
|||
// This file is not included with the IRCd standard include stack because
|
||||
// it requires symbols we can't forward declare without boost headers. It
|
||||
// is part of the <ircd/asio.h> stack which can be included in your
|
||||
// definition file if you need low level access to this socket API. The
|
||||
// client.h still offers higher level access to sockets without requiring
|
||||
// boost headers; please check that for satisfaction before including this.
|
||||
// definition file if you need low level access to this socket API.
|
||||
//
|
||||
// The public API is available in <ircd/net/sockpub.h> which is included with
|
||||
// the standard include group. It contains many features which may suit you
|
||||
// in lieu of direct access to this interface.
|
||||
|
||||
namespace ircd::net
|
||||
{
|
||||
struct socket;
|
||||
|
||||
std::shared_ptr<socket> connect(const ip::tcp::endpoint &remote, const milliseconds &timeout);
|
||||
|
||||
bool handle_verify(bool, asio::ssl::verify_context &) noexcept;
|
||||
extern asio::ssl::context sslv23_client;
|
||||
}
|
||||
|
||||
|
@ -67,10 +64,10 @@ struct ircd::net::socket
|
|||
bool timedout {false};
|
||||
|
||||
void call_user(const handler &, const error_code &ec) noexcept;
|
||||
bool handle_verify(bool, asio::ssl::verify_context &, std::string cn) noexcept;
|
||||
bool handle_verify(bool, asio::ssl::verify_context &, const connopts &) noexcept;
|
||||
void handle_handshake(std::weak_ptr<socket> wp, const connopts &, handler, const error_code &ec) noexcept;
|
||||
void handle_connect(std::weak_ptr<socket> wp, const connopts &, handler, const error_code &ec) noexcept;
|
||||
void handle_timeout(std::weak_ptr<socket> wp, const error_code &ec) noexcept;
|
||||
void handle_handshake(std::weak_ptr<socket> wp, handler, const error_code &ec) noexcept;
|
||||
void handle_connect(std::weak_ptr<socket> wp, std::string cn, handler, const error_code &ec) noexcept;
|
||||
void handle(std::weak_ptr<socket>, handler, const error_code &) noexcept;
|
||||
|
||||
public:
|
||||
|
@ -79,25 +76,8 @@ struct ircd::net::socket
|
|||
operator const SSL &() const;
|
||||
operator SSL &();
|
||||
|
||||
bool connected() const noexcept; // false on any sock errs
|
||||
endpoint remote() const; // getpeername(); throws if not conn
|
||||
endpoint local() const; // getsockname(); throws if not conn/bound
|
||||
size_t available() const; // throws on errors; use friend variant for noex..
|
||||
size_t readable() const; // throws on errors; ioctl
|
||||
size_t rbufsz() const; // throws on errors; SO_RCVBUF
|
||||
size_t wbufsz() const; // throws on errors; SO_SNDBUF
|
||||
size_t rlowat() const; // throws on errors; SO_RCVLOWAT
|
||||
size_t wlowat() const; // throws on errors; SO_SNDLOWWAT
|
||||
bool blocking() const; // throws on errors;
|
||||
bool nodelay() const; // throws on errors;
|
||||
|
||||
void rbufsz(const size_t &); // throws; set SO_RCVBUF bytes
|
||||
void wbufsz(const size_t &); // throws; set SO_RCVBUF bytes
|
||||
void rlowat(const size_t &); // throws; set SO_RCVLOWAT bytes
|
||||
void wlowat(const size_t &); // throws; set SO_SNDLOWAT bytes
|
||||
void blocking(const bool &); // throws; set blocking
|
||||
void nodelay(const bool &); // throws; TCP_NODELAY
|
||||
void flush(); // throws; toggles TCP_NODELAY
|
||||
|
||||
// low level read suite
|
||||
template<class iov> auto read_some(const iov &, xfer_handler);
|
||||
|
@ -112,6 +92,7 @@ struct ircd::net::socket
|
|||
template<class iov> auto write(const iov &);
|
||||
|
||||
// Timer for this socket
|
||||
bool has_timeout() const noexcept;
|
||||
void set_timeout(const milliseconds &, handler);
|
||||
void set_timeout(const milliseconds &);
|
||||
milliseconds cancel_timeout() noexcept;
|
||||
|
@ -121,17 +102,8 @@ struct ircd::net::socket
|
|||
void operator()(const wait_type &, handler);
|
||||
bool cancel() noexcept;
|
||||
|
||||
// SSL handshake after connect (untimed)
|
||||
void handshake(const handshake_type &, std::string cn, handler callback);
|
||||
void handshake(const handshake_type &, std::string cn);
|
||||
|
||||
// Connect to host (untimed)
|
||||
void connect(const endpoint &ep, handler callback);
|
||||
void connect(const endpoint &ep);
|
||||
|
||||
// Connect to host and handshake composit (timed)
|
||||
void open(const endpoint &ep, std::string cn, const milliseconds &timeout, handler callback);
|
||||
void open(const endpoint &ep, std::string cn, const milliseconds &timeout);
|
||||
void handshake(const connopts &, handler callback);
|
||||
void connect(const endpoint &, const connopts &, handler callback);
|
||||
|
||||
bool disconnect(const dc &type);
|
||||
|
||||
|
|
187
include/ircd/net/sockpub.h
Normal file
187
include/ircd/net/sockpub.h
Normal file
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright (C) 2017 Charybdis Development Team
|
||||
* Copyright (C) 2017 Jason Volk <jason@zemos.net>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice is present in all copies.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#define HAVE_IRCD_NET_SOCKPUB_H
|
||||
|
||||
// This is the public interface to net::socket because socket.h is not part of
|
||||
// the standard include group as it directly involves boost headers. For
|
||||
// direct access you may include <ircd/asio.h> in your definition file if
|
||||
// absolutely necessary.
|
||||
//
|
||||
// Any operation on the socket can trigger a pending error (i.e disconnection
|
||||
// userspace doesn't know about yet) and thus make any call after related to
|
||||
// the socket invalid and throw. We use noexcept here when there is a
|
||||
// reasonable default value returned instead of throwing. The goal there is to
|
||||
// reduce the number of places where the stack can blow up: for example, a
|
||||
// debug log call that prints the bytes available for reading. During testing
|
||||
// that may be the place of first observation where an exception keeps getting
|
||||
// thrown but during release that call won't be there and thus lays the
|
||||
// foundation for surprise heisenbugs.
|
||||
|
||||
namespace ircd::net
|
||||
{
|
||||
struct socket;
|
||||
struct sockopts;
|
||||
struct connopts;
|
||||
enum class dc;
|
||||
}
|
||||
|
||||
namespace ircd
|
||||
{
|
||||
using net::socket;
|
||||
}
|
||||
|
||||
namespace ircd::net
|
||||
{
|
||||
bool connected(const socket &) noexcept;
|
||||
size_t readable(const socket &);
|
||||
size_t available(const socket &) noexcept;
|
||||
ipport local_ipport(const socket &) noexcept;
|
||||
ipport remote_ipport(const socket &) noexcept;
|
||||
const_raw_buffer peer_cert_der(const mutable_raw_buffer &, const socket &);
|
||||
|
||||
size_t read(socket &, const ilist<mutable_buffer> &); // read_all
|
||||
size_t read(socket &, const iov<mutable_buffer> &); // read_all
|
||||
size_t read(socket &, iov<mutable_buffer> &); // read_some
|
||||
|
||||
size_t write(socket &, const ilist<const_buffer> &); // write_all
|
||||
size_t write(socket &, const iov<const_buffer> &); // write_all
|
||||
size_t write(socket &, iov<const_buffer> &); // write_some
|
||||
void flush(socket &);
|
||||
|
||||
bool disconnect(socket &, const dc &type) noexcept;
|
||||
bool disconnect(socket &) noexcept;
|
||||
|
||||
void open(socket &, const connopts &, std::function<void (std::exception_ptr)>);
|
||||
ctx::future<std::shared_ptr<socket>> open(const connopts &);
|
||||
}
|
||||
|
||||
/// Connection options structure. This is provided when making a client
|
||||
/// connection with a socket. Unless otherwise noted it usually has to
|
||||
/// remain in scope as a const reference for the duration of that process.
|
||||
/// Some of its members are also thin and will have to remain in scope along
|
||||
/// with it.
|
||||
struct ircd::net::connopts
|
||||
{
|
||||
/// Remote's hostname and port. This will be used for address resolution
|
||||
/// if an ipport is not also provided later. The hostname will also be used
|
||||
/// for certificate /CN verification if common_name is not provided later.
|
||||
net::hostport hostport;
|
||||
|
||||
/// Remote's resolved IP and port. Providing this skips DNS resolution if
|
||||
/// hostport is not given; required if so.
|
||||
net::ipport ipport;
|
||||
|
||||
/// The duration allowed for the TCP connection.
|
||||
milliseconds connect_timeout { 8000ms };
|
||||
|
||||
/// Pointer to a sockopts structure which will be applied to this socket
|
||||
/// if given. Defaults to null; no application is made.
|
||||
const sockopts *sopts { nullptr };
|
||||
|
||||
/// Option to toggle whether to perform the SSL handshake; you want true.
|
||||
bool handshake { true };
|
||||
|
||||
/// The duration allowed for the SSL handshake
|
||||
milliseconds handshake_timeout { 8000ms };
|
||||
|
||||
/// Option to toggle whether to perform any certificate verification; if
|
||||
/// false, everything no matter what is considered valid; you want true.
|
||||
bool verify_certificate { true };
|
||||
|
||||
/// Option to toggle whether to perform CN verification to ensure the
|
||||
/// certificate is signed to the actual host we want to talk to. When
|
||||
/// true, see the comments for `common_name`. Otherwise if false, any
|
||||
/// common_name will pass muster.
|
||||
bool verify_common_name { true };
|
||||
|
||||
/// The expected /CN of the target. This should be the remote's hostname,
|
||||
/// If it is empty then `hostport.host` is used. If the signed /CN has
|
||||
/// some rfc2818/rfc2459 wildcard we will properly match that for you.
|
||||
string_view common_name;
|
||||
|
||||
/// Option to toggle whether to allow self-signed certificates. This
|
||||
/// currently defaults to true to not break Matrix development but will
|
||||
/// likely change later and require setting to true for specific conns.
|
||||
bool allow_self_signed { true };
|
||||
|
||||
/// Option to toggle whether to allow self-signed certificate authorities
|
||||
/// in the chain. This is what corporate network nanny's may use to spy.
|
||||
bool allow_self_chain { false };
|
||||
};
|
||||
|
||||
// Socket options section
|
||||
namespace ircd::net
|
||||
{
|
||||
bool blocking(const socket &);
|
||||
bool nodelay(const socket &);
|
||||
bool keepalive(const socket &);
|
||||
time_t linger(const socket &);
|
||||
size_t read_bufsz(const socket &);
|
||||
size_t write_bufsz(const socket &);
|
||||
size_t read_lowat(const socket &);
|
||||
size_t write_lowat(const socket &);
|
||||
|
||||
void blocking(socket &, const bool &);
|
||||
void nodelay(socket &, const bool &);
|
||||
void keepalive(socket &, const bool &);
|
||||
void linger(socket &, const time_t &); // -1 is OFF; >= 0 is ON
|
||||
void read_bufsz(socket &, const size_t &bytes);
|
||||
void write_bufsz(socket &, const size_t &bytes);
|
||||
void read_lowat(socket &, const size_t &bytes);
|
||||
void write_lowat(socket &, const size_t &bytes);
|
||||
|
||||
void set(socket &, const sockopts &);
|
||||
}
|
||||
|
||||
/// Socket options convenience aggregate. This structure allows observation
|
||||
/// or manipulation of socket options all together. Pass an active socket to
|
||||
/// the constructor to observe all options. Use net::set(socket, sockopts) to
|
||||
/// set all non-ignored options.
|
||||
struct ircd::net::sockopts
|
||||
{
|
||||
/// Magic value to not set this option on a set() pass.
|
||||
static constexpr int8_t IGN { std::numeric_limits<int8_t>::min() };
|
||||
|
||||
int8_t blocking = IGN; // Simulates blocking behavior
|
||||
int8_t nodelay = IGN;
|
||||
int8_t keepalive = IGN;
|
||||
time_t linger = IGN; // -1 is OFF; >= 0 is ON
|
||||
ssize_t read_bufsz = IGN;
|
||||
ssize_t write_bufsz = IGN;
|
||||
ssize_t read_lowat = IGN;
|
||||
ssize_t write_lowat = IGN;
|
||||
|
||||
sockopts(const socket &); // Get options from socket
|
||||
sockopts() = default;
|
||||
};
|
||||
|
||||
/// Arguments for disconnecting.
|
||||
enum class ircd::net::dc
|
||||
{
|
||||
RST, ///< hardest immediate termination
|
||||
FIN, ///< sd graceful shutdown both directions
|
||||
FIN_SEND, ///< sd graceful shutdown send side
|
||||
FIN_RECV, ///< sd graceful shutdown recv side
|
||||
SSL_NOTIFY, ///< SSL close_notify (async, errors ignored)
|
||||
SSL_NOTIFY_YIELD, ///< SSL close_notify (yields context, throws)
|
||||
};
|
1201
ircd/net.cc
1201
ircd/net.cc
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue