1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-08-18 22:07:11 +02:00

Update ZMQ to current git.

This commit is contained in:
Sandu Liviu Catalin
2021-08-22 20:09:16 +03:00
parent b78b3e8ede
commit fa4644d00f
72 changed files with 1309 additions and 884 deletions

View File

@@ -35,69 +35,41 @@
#include <new>
#include "stream_engine.hpp"
#include "io_thread.hpp"
#include "platform.hpp"
#include "random.hpp"
#include "err.hpp"
#include "ip.hpp"
#include "address.hpp"
#include "session_base.hpp"
#include "vmci_address.hpp"
#include "vmci.hpp"
#include "session_base.hpp"
zmq::vmci_connecter_t::vmci_connecter_t (class io_thread_t *io_thread_,
class session_base_t *session_,
const options_t &options_,
const address_t *addr_,
address_t *addr_,
bool delayed_start_) :
own_t (io_thread_, options_),
io_object_t (io_thread_),
addr (addr_),
s (retired_fd),
handle_valid (false),
delayed_start (delayed_start_),
timer_started (false),
session (session_),
current_reconnect_ivl (options.reconnect_ivl)
stream_connecter_base_t (
io_thread_, session_, options_, addr_, delayed_start_),
_connect_timer_started (false)
{
zmq_assert (addr);
zmq_assert (addr->protocol == "vmci");
addr->to_string (endpoint);
socket = session->get_socket ();
zmq_assert (_addr->protocol == protocol_name::vmci);
}
zmq::vmci_connecter_t::~vmci_connecter_t ()
{
zmq_assert (!timer_started);
zmq_assert (!handle_valid);
zmq_assert (s == retired_fd);
}
void zmq::vmci_connecter_t::process_plug ()
{
if (delayed_start)
add_reconnect_timer ();
else
start_connecting ();
zmq_assert (!_connect_timer_started);
}
void zmq::vmci_connecter_t::process_term (int linger_)
{
if (timer_started) {
cancel_timer (reconnect_timer_id);
timer_started = false;
if (_connect_timer_started) {
cancel_timer (connect_timer_id);
_connect_timer_started = false;
}
if (handle_valid) {
rm_fd (handle);
handle_valid = false;
}
if (s != retired_fd)
close ();
own_t::process_term (linger_);
stream_connecter_base_t::process_term (linger_);
}
void zmq::vmci_connecter_t::in_event ()
@@ -110,9 +82,26 @@ void zmq::vmci_connecter_t::in_event ()
void zmq::vmci_connecter_t::out_event ()
{
fd_t fd = connect ();
rm_fd (handle);
handle_valid = false;
if (_connect_timer_started) {
cancel_timer (connect_timer_id);
_connect_timer_started = false;
}
// TODO this is still very similar to (t)ipc_connecter_t, maybe the
// differences can be factored out
rm_handle ();
const fd_t fd = connect ();
if (fd == retired_fd
&& ((options.reconnect_stop & ZMQ_RECONNECT_STOP_CONN_REFUSED)
&& errno == ECONNREFUSED)) {
send_conn_failed (_session);
close ();
terminate ();
return;
}
// Handle the error condition by attempt to reconnect.
if (fd == retired_fd) {
@@ -135,148 +124,154 @@ void zmq::vmci_connecter_t::out_event ()
#endif
}
// Create the engine object for this connection.
stream_engine_t *engine = new (std::nothrow) stream_engine_t (
fd, options, make_unconnected_bind_endpoint_pair (endpoint));
alloc_assert (engine);
create_engine (
fd, zmq::vmci_connecter_t::get_socket_name (fd, socket_end_local));
}
// Attach the engine to the corresponding session object.
send_attach (session, engine);
std::string
zmq::vmci_connecter_t::get_socket_name (zmq::fd_t fd_,
socket_end_t socket_end_) const
{
struct sockaddr_storage ss;
const zmq_socklen_t sl = get_socket_address (fd_, socket_end_, &ss);
if (sl == 0) {
return std::string ();
}
// Shut the connecter down.
terminate ();
socket->event_connected (make_unconnected_bind_endpoint_pair (endpoint),
fd);
const vmci_address_t addr (reinterpret_cast<struct sockaddr *> (&ss), sl,
this->get_ctx ());
std::string address_string;
addr.to_string (address_string);
return address_string;
}
void zmq::vmci_connecter_t::timer_event (int id_)
{
zmq_assert (id_ == reconnect_timer_id);
timer_started = false;
start_connecting ();
if (id_ == connect_timer_id) {
_connect_timer_started = false;
rm_handle ();
close ();
add_reconnect_timer ();
} else
stream_connecter_base_t::timer_event (id_);
}
void zmq::vmci_connecter_t::start_connecting ()
{
// Open the connecting socket.
int rc = open ();
const int rc = open ();
// Connect may succeed in synchronous manner.
if (rc == 0) {
handle = add_fd (s);
handle_valid = true;
_handle = add_fd (_s);
out_event ();
}
// Connection establishment may be delayed. Poll for its completion.
else if (rc == -1 && errno == EINPROGRESS) {
_handle = add_fd (_s);
set_pollout (_handle);
_socket->event_connect_delayed (
make_unconnected_connect_endpoint_pair (_endpoint), zmq_errno ());
// add userspace connect timeout
add_connect_timer ();
}
// Handle any other error condition by eventual reconnect.
else {
if (s != retired_fd)
if (_s != retired_fd)
close ();
add_reconnect_timer ();
}
}
void zmq::vmci_connecter_t::add_reconnect_timer ()
void zmq::vmci_connecter_t::add_connect_timer ()
{
if (options.reconnect_ivl > 0) {
int rc_ivl = get_new_reconnect_ivl ();
add_timer (rc_ivl, reconnect_timer_id);
socket->event_connect_retried (
make_unconnected_bind_endpoint_pair (endpoint), rc_ivl);
timer_started = true;
if (options.connect_timeout > 0) {
add_timer (options.connect_timeout, connect_timer_id);
_connect_timer_started = true;
}
}
int zmq::vmci_connecter_t::get_new_reconnect_ivl ()
{
// The new interval is the current interval + random value.
int this_interval =
current_reconnect_ivl + (generate_random () % options.reconnect_ivl);
// Only change the current reconnect interval if the maximum reconnect
// interval was set and if it's larger than the reconnect interval.
if (options.reconnect_ivl_max > 0
&& options.reconnect_ivl_max > options.reconnect_ivl) {
// Calculate the next interval
current_reconnect_ivl = current_reconnect_ivl * 2;
if (current_reconnect_ivl >= options.reconnect_ivl_max) {
current_reconnect_ivl = options.reconnect_ivl_max;
}
}
return this_interval;
}
int zmq::vmci_connecter_t::open ()
{
zmq_assert (s == retired_fd);
zmq_assert (_s == retired_fd);
int family = this->get_ctx ()->get_vmci_socket_family ();
if (family == -1)
return -1;
// Resolve the address
if (_addr->resolved.vmci_addr != NULL) {
LIBZMQ_DELETE (_addr->resolved.vmci_addr);
}
// Create the socket.
s = open_socket (family, SOCK_STREAM, 0);
#ifdef ZMQ_HAVE_WINDOWS
if (s == INVALID_SOCKET) {
errno = wsa_error_to_errno (WSAGetLastError ());
_addr->resolved.vmci_addr =
new (std::nothrow) vmci_address_t (this->get_ctx ());
alloc_assert (_addr->resolved.vmci_addr);
_s = vmci_open_socket (_addr->address.c_str (), options,
_addr->resolved.vmci_addr);
if (_s == retired_fd) {
// TODO we should emit some event in this case!
LIBZMQ_DELETE (_addr->resolved.vmci_addr);
return -1;
}
#else
if (s == -1)
return -1;
#endif
zmq_assert (_addr->resolved.vmci_addr != NULL);
// Set the socket to non-blocking mode so that we get async connect().
unblock_socket (_s);
const vmci_address_t *const vmci_addr = _addr->resolved.vmci_addr;
int rc;
// Connect to the remote peer.
int rc = ::connect (s, addr->resolved.vmci_addr->addr (),
addr->resolved.vmci_addr->addrlen ());
// Connect was successful immediately.
if (rc == 0)
return 0;
// Forward the error.
return -1;
}
void zmq::vmci_connecter_t::close ()
{
zmq_assert (s != retired_fd);
#ifdef ZMQ_HAVE_WINDOWS
const int rc = closesocket (s);
wsa_assert (rc != SOCKET_ERROR);
#if defined ZMQ_HAVE_VXWORKS
rc = ::connect (_s, (sockaddr *) vmci_addr->addr (), vmci_addr->addrlen ());
#else
const int rc = ::close (s);
errno_assert (rc == 0);
rc = ::connect (_s, vmci_addr->addr (), vmci_addr->addrlen ());
#endif
socket->event_closed (make_unconnected_bind_endpoint_pair (endpoint), s);
s = retired_fd;
// Connect was successful immediately.
if (rc == 0) {
return 0;
}
// Translate error codes indicating asynchronous connect has been
// launched to a uniform EINPROGRESS.
#ifdef ZMQ_HAVE_WINDOWS
const int last_error = WSAGetLastError ();
if (last_error == WSAEINPROGRESS || last_error == WSAEWOULDBLOCK)
errno = EINPROGRESS;
else
errno = wsa_error_to_errno (last_error);
#else
if (errno == EINTR)
errno = EINPROGRESS;
#endif
return -1;
}
zmq::fd_t zmq::vmci_connecter_t::connect ()
{
// Following code should handle both Berkeley-derived socket
// implementations and Solaris.
// Async connect has finished. Check whether an error occurred
int err = 0;
#if defined ZMQ_HAVE_HPUX
int len = sizeof (err);
#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_VXWORKS
int len = sizeof err;
#else
socklen_t len = sizeof (err);
socklen_t len = sizeof err;
#endif
int rc = getsockopt (s, SOL_SOCKET, SO_ERROR, (char *) &err, &len);
const int rc = getsockopt (_s, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char *> (&err), &len);
// Assert if the error was caused by 0MQ bug.
// Networking problems are OK. No need to assert.
#ifdef ZMQ_HAVE_WINDOWS
zmq_assert (rc == 0);
if (err != 0) {
if (err != WSAECONNREFUSED && err != WSAETIMEDOUT
&& err != WSAECONNABORTED && err != WSAEHOSTUNREACH
&& err != WSAENETUNREACH && err != WSAENETDOWN && err != WSAEACCES
&& err != WSAEINVAL && err != WSAEADDRINUSE
&& err != WSAECONNRESET) {
if (err == WSAEBADF || err == WSAENOPROTOOPT || err == WSAENOTSOCK
|| err == WSAENOBUFS) {
wsa_assert_no (err);
}
errno = wsa_error_to_errno (err);
return retired_fd;
}
#else
@@ -286,16 +281,20 @@ zmq::fd_t zmq::vmci_connecter_t::connect ()
err = errno;
if (err != 0) {
errno = err;
errno_assert (errno == ECONNREFUSED || errno == ECONNRESET
|| errno == ETIMEDOUT || errno == EHOSTUNREACH
|| errno == ENETUNREACH || errno == ENETDOWN
|| errno == EINVAL);
#if !defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE
errno_assert (errno != EBADF && errno != ENOPROTOOPT
&& errno != ENOTSOCK && errno != ENOBUFS);
#else
errno_assert (errno != ENOPROTOOPT && errno != ENOTSOCK
&& errno != ENOBUFS);
#endif
return retired_fd;
}
#endif
fd_t result = s;
s = retired_fd;
// Return the newly connected socket.
const fd_t result = _s;
_s = retired_fd;
return result;
}