Refactor of listen alerts for separated fields address and port (#778)
Refactor of listen alerts for separated fields address and port
This commit is contained in:
parent
cdd067fe4e
commit
42a9022065
|
@ -1,3 +1,4 @@
|
||||||
|
* separated address and port fields in listen alerts
|
||||||
* added support for parsing new x.pe parameter from BEP 9
|
* added support for parsing new x.pe parameter from BEP 9
|
||||||
* peer_blocked_alert now derives from peer_alert
|
* peer_blocked_alert now derives from peer_alert
|
||||||
* transitioned exception types to system_error
|
* transitioned exception types to system_error
|
||||||
|
|
|
@ -480,7 +480,11 @@ void bind_alert()
|
||||||
|
|
||||||
class_<listen_failed_alert, bases<alert>, noncopyable>(
|
class_<listen_failed_alert, bases<alert>, noncopyable>(
|
||||||
"listen_failed_alert", no_init)
|
"listen_failed_alert", no_init)
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
.def_readonly("endpoint", &listen_failed_alert::endpoint)
|
.def_readonly("endpoint", &listen_failed_alert::endpoint)
|
||||||
|
#endif
|
||||||
|
.def_readonly("address", &listen_failed_alert::address)
|
||||||
|
.def_readonly("port", &listen_failed_alert::port)
|
||||||
.def("listen_interface", &listen_failed_alert::listen_interface)
|
.def("listen_interface", &listen_failed_alert::listen_interface)
|
||||||
.def_readonly("error", &listen_failed_alert::error)
|
.def_readonly("error", &listen_failed_alert::error)
|
||||||
.def_readonly("operation", &listen_failed_alert::operation)
|
.def_readonly("operation", &listen_failed_alert::operation)
|
||||||
|
@ -489,7 +493,12 @@ void bind_alert()
|
||||||
|
|
||||||
class_<listen_succeeded_alert, bases<alert>, noncopyable>(
|
class_<listen_succeeded_alert, bases<alert>, noncopyable>(
|
||||||
"listen_succeeded_alert", no_init)
|
"listen_succeeded_alert", no_init)
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
.def_readonly("endpoint", &listen_succeeded_alert::endpoint)
|
.def_readonly("endpoint", &listen_succeeded_alert::endpoint)
|
||||||
|
#endif
|
||||||
|
.def_readonly("address", &listen_succeeded_alert::address)
|
||||||
|
.def_readonly("port", &listen_succeeded_alert::port)
|
||||||
|
.def_readonly("sock_type", &listen_succeeded_alert::sock_type)
|
||||||
;
|
;
|
||||||
|
|
||||||
class_<portmap_error_alert, bases<alert>, noncopyable>(
|
class_<portmap_error_alert, bases<alert>, noncopyable>(
|
||||||
|
|
|
@ -1242,9 +1242,15 @@ namespace libtorrent
|
||||||
};
|
};
|
||||||
|
|
||||||
// This alert is generated when none of the ports, given in the port range, to
|
// This alert is generated when none of the ports, given in the port range, to
|
||||||
// session can be opened for listening. The ``endpoint`` member is the
|
// session can be opened for listening. The ``listen_interface`` member is the
|
||||||
// interface and port that failed, ``error`` is the error code describing
|
// interface that failed, ``error`` is the error code describing the failure.
|
||||||
// the failure.
|
//
|
||||||
|
// In the case an endpoint was created before generating the alert, it is
|
||||||
|
// represented by ``address`` and ``port``. The combinations of socket type
|
||||||
|
// and operation in which such address and port are not valid are:
|
||||||
|
// accept - i2p
|
||||||
|
// accept - socks5
|
||||||
|
// enum_if - tcp
|
||||||
//
|
//
|
||||||
// libtorrent may sometimes try to listen on port 0, if all other ports failed.
|
// libtorrent may sometimes try to listen on port 0, if all other ports failed.
|
||||||
// Port 0 asks the operating system to pick a port that's free). If that fails
|
// Port 0 asks the operating system to pick a port that's free). If that fails
|
||||||
|
@ -1255,6 +1261,15 @@ namespace libtorrent
|
||||||
enum socket_type_t { tcp, tcp_ssl, udp, i2p, socks5, utp_ssl };
|
enum socket_type_t { tcp, tcp_ssl, udp, i2p, socks5, utp_ssl };
|
||||||
|
|
||||||
// internal
|
// internal
|
||||||
|
listen_failed_alert(
|
||||||
|
aux::stack_allocator& alloc
|
||||||
|
, std::string const& iface
|
||||||
|
, libtorrent::address const& listen_addr
|
||||||
|
, int listen_port
|
||||||
|
, int op
|
||||||
|
, error_code const& ec
|
||||||
|
, socket_type_t t);
|
||||||
|
|
||||||
listen_failed_alert(
|
listen_failed_alert(
|
||||||
aux::stack_allocator& alloc
|
aux::stack_allocator& alloc
|
||||||
, std::string const& iface
|
, std::string const& iface
|
||||||
|
@ -1263,6 +1278,21 @@ namespace libtorrent
|
||||||
, error_code const& ec
|
, error_code const& ec
|
||||||
, socket_type_t t);
|
, socket_type_t t);
|
||||||
|
|
||||||
|
listen_failed_alert(
|
||||||
|
aux::stack_allocator& alloc
|
||||||
|
, std::string const& iface
|
||||||
|
, udp::endpoint const& ep
|
||||||
|
, int op
|
||||||
|
, error_code const& ec
|
||||||
|
, socket_type_t t);
|
||||||
|
|
||||||
|
listen_failed_alert(
|
||||||
|
aux::stack_allocator& alloc
|
||||||
|
, std::string const& iface
|
||||||
|
, int op
|
||||||
|
, error_code const& ec
|
||||||
|
, socket_type_t t);
|
||||||
|
|
||||||
TORRENT_DEFINE_ALERT_PRIO(listen_failed_alert, 48)
|
TORRENT_DEFINE_ALERT_PRIO(listen_failed_alert, 48)
|
||||||
|
|
||||||
static const int static_category = alert::status_notification | alert::error_notification;
|
static const int static_category = alert::status_notification | alert::error_notification;
|
||||||
|
@ -1285,8 +1315,18 @@ namespace libtorrent
|
||||||
// the type of listen socket this alert refers to.
|
// the type of listen socket this alert refers to.
|
||||||
socket_type_t sock_type;
|
socket_type_t sock_type;
|
||||||
|
|
||||||
|
// the address libtorrent attempted to listen on
|
||||||
|
// see alert's documentation for validity of this value
|
||||||
|
libtorrent::address address;
|
||||||
|
|
||||||
|
// the port libtorrent attempted to listen on
|
||||||
|
// see alert's documentation for validity of this value
|
||||||
|
int port;
|
||||||
|
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
// the address and port libtorrent attempted to listen on
|
// the address and port libtorrent attempted to listen on
|
||||||
tcp::endpoint endpoint;
|
tcp::endpoint endpoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::reference_wrapper<aux::stack_allocator const> m_alloc;
|
std::reference_wrapper<aux::stack_allocator const> m_alloc;
|
||||||
|
@ -1301,7 +1341,17 @@ namespace libtorrent
|
||||||
enum socket_type_t { tcp, tcp_ssl, udp, i2p, socks5, utp_ssl };
|
enum socket_type_t { tcp, tcp_ssl, udp, i2p, socks5, utp_ssl };
|
||||||
|
|
||||||
// internal
|
// internal
|
||||||
listen_succeeded_alert(aux::stack_allocator& alloc, tcp::endpoint const& ep
|
listen_succeeded_alert(aux::stack_allocator& alloc
|
||||||
|
, libtorrent::address const& listen_addr
|
||||||
|
, int listen_port
|
||||||
|
, socket_type_t t);
|
||||||
|
|
||||||
|
listen_succeeded_alert(aux::stack_allocator& alloc
|
||||||
|
, tcp::endpoint const& ep
|
||||||
|
, socket_type_t t);
|
||||||
|
|
||||||
|
listen_succeeded_alert(aux::stack_allocator& alloc
|
||||||
|
, udp::endpoint const& ep
|
||||||
, socket_type_t t);
|
, socket_type_t t);
|
||||||
|
|
||||||
TORRENT_DEFINE_ALERT_PRIO(listen_succeeded_alert, 49)
|
TORRENT_DEFINE_ALERT_PRIO(listen_succeeded_alert, 49)
|
||||||
|
@ -1309,9 +1359,18 @@ namespace libtorrent
|
||||||
static const int static_category = alert::status_notification;
|
static const int static_category = alert::status_notification;
|
||||||
virtual std::string message() const override;
|
virtual std::string message() const override;
|
||||||
|
|
||||||
|
// the address libtorrent ended up listening on. This address
|
||||||
|
// refers to the local interface.
|
||||||
|
libtorrent::address address;
|
||||||
|
|
||||||
|
// the port libtorrent ended up listening on.
|
||||||
|
int port;
|
||||||
|
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
// the endpoint libtorrent ended up listening on. The address
|
// the endpoint libtorrent ended up listening on. The address
|
||||||
// refers to the local interface and the port is the listen port.
|
// refers to the local interface and the port is the listen port.
|
||||||
tcp::endpoint endpoint;
|
tcp::endpoint endpoint;
|
||||||
|
#endif
|
||||||
|
|
||||||
// the type of listen socket this alert refers to.
|
// the type of listen socket this alert refers to.
|
||||||
socket_type_t sock_type;
|
socket_type_t sock_type;
|
||||||
|
|
|
@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
TORRENT_EXTRA_EXPORT std::string print_address(address const& addr);
|
TORRENT_EXTRA_EXPORT std::string print_address(address const& addr);
|
||||||
|
TORRENT_EXTRA_EXPORT std::string print_endpoint(address const& addr, int port);
|
||||||
TORRENT_EXTRA_EXPORT std::string print_endpoint(tcp::endpoint const& ep);
|
TORRENT_EXTRA_EXPORT std::string print_endpoint(tcp::endpoint const& ep);
|
||||||
TORRENT_EXTRA_EXPORT std::string print_endpoint(udp::endpoint const& ep);
|
TORRENT_EXTRA_EXPORT std::string print_endpoint(udp::endpoint const& ep);
|
||||||
TORRENT_EXTRA_EXPORT tcp::endpoint parse_endpoint(std::string str, error_code& ec);
|
TORRENT_EXTRA_EXPORT tcp::endpoint parse_endpoint(std::string str, error_code& ec);
|
||||||
|
|
|
@ -200,8 +200,8 @@ TORRENT_TEST(socks4_tcp_listen_alert)
|
||||||
{
|
{
|
||||||
if (a->sock_type == listen_succeeded_alert::socks5)
|
if (a->sock_type == listen_succeeded_alert::socks5)
|
||||||
{
|
{
|
||||||
TEST_EQUAL(a->endpoint.address(), addr("50.50.50.50"));
|
TEST_EQUAL(a->address, addr("50.50.50.50"));
|
||||||
TEST_EQUAL(a->endpoint.port(), 6881);
|
TEST_EQUAL(a->port, 6881);
|
||||||
listen_alert = true;
|
listen_alert = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,8 +230,8 @@ TORRENT_TEST(socks5_tcp_listen_alert)
|
||||||
{
|
{
|
||||||
if (a->sock_type == listen_succeeded_alert::socks5)
|
if (a->sock_type == listen_succeeded_alert::socks5)
|
||||||
{
|
{
|
||||||
TEST_EQUAL(a->endpoint.address(), addr("50.50.50.50"));
|
TEST_EQUAL(a->address, addr("50.50.50.50"));
|
||||||
TEST_EQUAL(a->endpoint.port(), 6881);
|
TEST_EQUAL(a->port, 6881);
|
||||||
listen_alert = true;
|
listen_alert = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,7 +267,7 @@ TORRENT_TEST(socks5_tcp_announce)
|
||||||
{
|
{
|
||||||
if (a->sock_type == listen_succeeded_alert::socks5)
|
if (a->sock_type == listen_succeeded_alert::socks5)
|
||||||
{
|
{
|
||||||
alert_port = a->endpoint.port();
|
alert_port = a->port;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -829,18 +829,70 @@ namespace libtorrent {
|
||||||
listen_failed_alert::listen_failed_alert(
|
listen_failed_alert::listen_failed_alert(
|
||||||
aux::stack_allocator& alloc
|
aux::stack_allocator& alloc
|
||||||
, std::string const& iface
|
, std::string const& iface
|
||||||
, tcp::endpoint const& ep
|
, libtorrent::address const& listen_addr
|
||||||
|
, int listen_port
|
||||||
, int op
|
, int op
|
||||||
, error_code const& ec
|
, error_code const& ec
|
||||||
, socket_type_t t)
|
, socket_type_t t)
|
||||||
: error(ec)
|
: error(ec)
|
||||||
, operation(op)
|
, operation(op)
|
||||||
, sock_type(t)
|
, sock_type(t)
|
||||||
, endpoint(ep)
|
, address(listen_addr)
|
||||||
|
, port(listen_port)
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
|
, endpoint(listen_addr, listen_port)
|
||||||
|
#endif
|
||||||
, m_alloc(alloc)
|
, m_alloc(alloc)
|
||||||
, m_interface_idx(alloc.copy_string(iface))
|
, m_interface_idx(alloc.copy_string(iface))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
listen_failed_alert::listen_failed_alert(
|
||||||
|
aux::stack_allocator& alloc
|
||||||
|
, std::string const& iface
|
||||||
|
, tcp::endpoint const& ep
|
||||||
|
, int op
|
||||||
|
, error_code const& ec
|
||||||
|
, socket_type_t t)
|
||||||
|
: listen_failed_alert(alloc
|
||||||
|
, iface
|
||||||
|
, ep.address()
|
||||||
|
, ep.port()
|
||||||
|
, op
|
||||||
|
, ec
|
||||||
|
, t)
|
||||||
|
{}
|
||||||
|
|
||||||
|
listen_failed_alert::listen_failed_alert(
|
||||||
|
aux::stack_allocator& alloc
|
||||||
|
, std::string const& iface
|
||||||
|
, udp::endpoint const& ep
|
||||||
|
, int op
|
||||||
|
, error_code const& ec
|
||||||
|
, socket_type_t t)
|
||||||
|
: listen_failed_alert(alloc
|
||||||
|
, iface
|
||||||
|
, ep.address()
|
||||||
|
, ep.port()
|
||||||
|
, op
|
||||||
|
, ec
|
||||||
|
, t)
|
||||||
|
{}
|
||||||
|
|
||||||
|
listen_failed_alert::listen_failed_alert(
|
||||||
|
aux::stack_allocator& alloc
|
||||||
|
, std::string const& iface
|
||||||
|
, int op
|
||||||
|
, error_code const& ec
|
||||||
|
, socket_type_t t)
|
||||||
|
: listen_failed_alert(alloc
|
||||||
|
, iface
|
||||||
|
, libtorrent::address()
|
||||||
|
, 0
|
||||||
|
, op
|
||||||
|
, ec
|
||||||
|
, t)
|
||||||
|
{}
|
||||||
|
|
||||||
char const* listen_failed_alert::listen_interface() const
|
char const* listen_failed_alert::listen_interface() const
|
||||||
{
|
{
|
||||||
return m_alloc.get().ptr(m_interface_idx);
|
return m_alloc.get().ptr(m_interface_idx);
|
||||||
|
@ -861,7 +913,7 @@ namespace libtorrent {
|
||||||
};
|
};
|
||||||
char ret[300];
|
char ret[300];
|
||||||
std::snprintf(ret, sizeof(ret), "listening on %s (device: %s) failed: [%s] [%s] %s"
|
std::snprintf(ret, sizeof(ret), "listening on %s (device: %s) failed: [%s] [%s] %s"
|
||||||
, print_endpoint(endpoint).c_str()
|
, print_endpoint(address, port).c_str()
|
||||||
, listen_interface()
|
, listen_interface()
|
||||||
, op_str[operation]
|
, op_str[operation]
|
||||||
, sock_type_str[sock_type]
|
, sock_type_str[sock_type]
|
||||||
|
@ -916,17 +968,41 @@ namespace libtorrent {
|
||||||
}
|
}
|
||||||
|
|
||||||
listen_succeeded_alert::listen_succeeded_alert(aux::stack_allocator&
|
listen_succeeded_alert::listen_succeeded_alert(aux::stack_allocator&
|
||||||
, tcp::endpoint const& ep, socket_type_t t)
|
, libtorrent::address const& listen_addr
|
||||||
: endpoint(ep)
|
, int listen_port
|
||||||
|
, socket_type_t t)
|
||||||
|
: address(listen_addr)
|
||||||
|
, port(listen_port)
|
||||||
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
|
, endpoint(listen_addr, listen_port)
|
||||||
|
#endif
|
||||||
, sock_type(t)
|
, sock_type(t)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
listen_succeeded_alert::listen_succeeded_alert(aux::stack_allocator& alloc
|
||||||
|
, tcp::endpoint const& ep
|
||||||
|
, socket_type_t t)
|
||||||
|
: listen_succeeded_alert(alloc
|
||||||
|
, ep.address()
|
||||||
|
, ep.port()
|
||||||
|
, t)
|
||||||
|
{}
|
||||||
|
|
||||||
|
listen_succeeded_alert::listen_succeeded_alert(aux::stack_allocator& alloc
|
||||||
|
, udp::endpoint const& ep
|
||||||
|
, socket_type_t t)
|
||||||
|
: listen_succeeded_alert(alloc
|
||||||
|
, ep.address()
|
||||||
|
, ep.port()
|
||||||
|
, t)
|
||||||
|
{}
|
||||||
|
|
||||||
std::string listen_succeeded_alert::message() const
|
std::string listen_succeeded_alert::message() const
|
||||||
{
|
{
|
||||||
char const* type_str[] = { "TCP", "SSL/TCP", "UDP", "i2p", "socks5", "SSL/uTP" };
|
char const* type_str[] = { "TCP", "SSL/TCP", "UDP", "i2p", "socks5", "SSL/uTP" };
|
||||||
char ret[200];
|
char ret[200];
|
||||||
std::snprintf(ret, sizeof(ret), "successfully listening on [%s] %s"
|
std::snprintf(ret, sizeof(ret), "successfully listening on [%s] %s"
|
||||||
, type_str[sock_type], print_endpoint(endpoint).c_str());
|
, type_str[sock_type], print_endpoint(address, port).c_str());
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1897,7 +1897,7 @@ namespace aux {
|
||||||
if (m_alerts.should_post<listen_failed_alert>())
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
{
|
{
|
||||||
m_alerts.emplace_alert<listen_failed_alert>(device
|
m_alerts.emplace_alert<listen_failed_alert>(device
|
||||||
, tcp::endpoint(), listen_failed_alert::enum_if, ec
|
, listen_failed_alert::enum_if, ec
|
||||||
, listen_failed_alert::tcp);
|
, listen_failed_alert::tcp);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -1964,7 +1964,7 @@ namespace aux {
|
||||||
: listen_succeeded_alert::udp;
|
: listen_succeeded_alert::udp;
|
||||||
|
|
||||||
m_alerts.emplace_alert<listen_succeeded_alert>(
|
m_alerts.emplace_alert<listen_succeeded_alert>(
|
||||||
tcp::endpoint(udp_ep.address(), udp_ep.port()), socket_type);
|
udp_ep, socket_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2066,7 +2066,7 @@ namespace aux {
|
||||||
if (e == boost::asio::error::operation_aborted) return;
|
if (e == boost::asio::error::operation_aborted) return;
|
||||||
if (m_alerts.should_post<listen_failed_alert>())
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
m_alerts.emplace_alert<listen_failed_alert>("socks5"
|
m_alerts.emplace_alert<listen_failed_alert>("socks5"
|
||||||
, tcp::endpoint(), listen_failed_alert::accept, e
|
, listen_failed_alert::accept, e
|
||||||
, listen_failed_alert::socks5);
|
, listen_failed_alert::socks5);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2099,7 +2099,7 @@ namespace aux {
|
||||||
{
|
{
|
||||||
if (m_alerts.should_post<listen_failed_alert>())
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
m_alerts.emplace_alert<listen_failed_alert>("socks5"
|
m_alerts.emplace_alert<listen_failed_alert>("socks5"
|
||||||
, tcp::endpoint(), listen_failed_alert::accept, e
|
, listen_failed_alert::accept, e
|
||||||
, listen_failed_alert::socks5);
|
, listen_failed_alert::socks5);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2188,7 +2188,6 @@ namespace aux {
|
||||||
if (m_alerts.should_post<listen_failed_alert>())
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
{
|
{
|
||||||
m_alerts.emplace_alert<listen_failed_alert>("i2p"
|
m_alerts.emplace_alert<listen_failed_alert>("i2p"
|
||||||
, tcp::endpoint()
|
|
||||||
, listen_failed_alert::accept
|
, listen_failed_alert::accept
|
||||||
, e, listen_failed_alert::i2p);
|
, e, listen_failed_alert::i2p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,23 +64,27 @@ namespace libtorrent
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string print_endpoint(tcp::endpoint const& ep)
|
std::string print_endpoint(address const& addr, int port)
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
char buf[200];
|
char buf[200];
|
||||||
address const& addr = ep.address();
|
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
if (addr.is_v6())
|
if (addr.is_v6())
|
||||||
std::snprintf(buf, sizeof(buf), "[%s]:%d", addr.to_string(ec).c_str(), ep.port());
|
std::snprintf(buf, sizeof(buf), "[%s]:%d", addr.to_string(ec).c_str(), port);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
std::snprintf(buf, sizeof(buf), "%s:%d", addr.to_string(ec).c_str(), ep.port());
|
std::snprintf(buf, sizeof(buf), "%s:%d", addr.to_string(ec).c_str(), port);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string print_endpoint(tcp::endpoint const& ep)
|
||||||
|
{
|
||||||
|
return print_endpoint(ep.address(), ep.port());
|
||||||
|
}
|
||||||
|
|
||||||
std::string print_endpoint(udp::endpoint const& ep)
|
std::string print_endpoint(udp::endpoint const& ep)
|
||||||
{
|
{
|
||||||
return print_endpoint(tcp::endpoint(ep.address(), ep.port()));
|
return print_endpoint(ep.address(), ep.port());
|
||||||
}
|
}
|
||||||
|
|
||||||
tcp::endpoint parse_endpoint(std::string str, error_code& ec)
|
tcp::endpoint parse_endpoint(std::string str, error_code& ec)
|
||||||
|
|
Loading…
Reference in New Issue