/src/libzmq/src/stream_connecter_base.cpp
Line | Count | Source |
1 | | /* SPDX-License-Identifier: MPL-2.0 */ |
2 | | |
3 | | #include "precompiled.hpp" |
4 | | #include "stream_connecter_base.hpp" |
5 | | #include "session_base.hpp" |
6 | | #include "address.hpp" |
7 | | #include "random.hpp" |
8 | | #include "zmtp_engine.hpp" |
9 | | #include "raw_engine.hpp" |
10 | | |
11 | | #ifndef ZMQ_HAVE_WINDOWS |
12 | | #include <unistd.h> |
13 | | #else |
14 | | #include <winsock2.h> |
15 | | #endif |
16 | | |
17 | | #include <limits> |
18 | | #include <new> |
19 | | |
20 | | zmq::stream_connecter_base_t::stream_connecter_base_t ( |
21 | | zmq::io_thread_t *io_thread_, |
22 | | zmq::session_base_t *session_, |
23 | | const zmq::options_t &options_, |
24 | | zmq::address_t *addr_, |
25 | | bool delayed_start_) : |
26 | 0 | own_t (io_thread_, options_), |
27 | 0 | io_object_t (io_thread_), |
28 | 0 | _addr (addr_), |
29 | 0 | _s (retired_fd), |
30 | 0 | _handle (static_cast<handle_t> (NULL)), |
31 | 0 | _socket (session_->get_socket ()), |
32 | 0 | _delayed_start (delayed_start_), |
33 | 0 | _reconnect_timer_started (false), |
34 | 0 | _current_reconnect_ivl (-1), |
35 | 0 | _session (session_) |
36 | 0 | { |
37 | 0 | zmq_assert (_addr); |
38 | 0 | _addr->to_string (_endpoint); |
39 | | // TODO the return value is unused! what if it fails? if this is impossible |
40 | | // or does not matter, change such that endpoint in initialized using an |
41 | | // initializer, and make endpoint const |
42 | 0 | } |
43 | | |
44 | | zmq::stream_connecter_base_t::~stream_connecter_base_t () |
45 | 0 | { |
46 | 0 | zmq_assert (!_reconnect_timer_started); |
47 | 0 | zmq_assert (!_handle); |
48 | 0 | zmq_assert (_s == retired_fd); |
49 | 0 | } |
50 | | |
51 | | void zmq::stream_connecter_base_t::process_plug () |
52 | 0 | { |
53 | 0 | if (_delayed_start) |
54 | 0 | add_reconnect_timer (); |
55 | 0 | else |
56 | 0 | start_connecting (); |
57 | 0 | } |
58 | | |
59 | | void zmq::stream_connecter_base_t::process_term (int linger_) |
60 | 0 | { |
61 | 0 | if (_reconnect_timer_started) { |
62 | 0 | cancel_timer (reconnect_timer_id); |
63 | 0 | _reconnect_timer_started = false; |
64 | 0 | } |
65 | |
|
66 | 0 | if (_handle) { |
67 | 0 | rm_handle (); |
68 | 0 | } |
69 | |
|
70 | 0 | if (_s != retired_fd) |
71 | 0 | close (); |
72 | |
|
73 | 0 | own_t::process_term (linger_); |
74 | 0 | } |
75 | | |
76 | | void zmq::stream_connecter_base_t::add_reconnect_timer () |
77 | 0 | { |
78 | 0 | if (options.reconnect_ivl > 0) { |
79 | 0 | const int interval = get_new_reconnect_ivl (); |
80 | 0 | add_timer (interval, reconnect_timer_id); |
81 | 0 | _socket->event_connect_retried ( |
82 | 0 | make_unconnected_connect_endpoint_pair (_endpoint), interval); |
83 | 0 | _reconnect_timer_started = true; |
84 | 0 | } |
85 | 0 | } |
86 | | |
87 | | int zmq::stream_connecter_base_t::get_new_reconnect_ivl () |
88 | 0 | { |
89 | 0 | if (options.reconnect_ivl_max > 0) { |
90 | 0 | int candidate_interval = 0; |
91 | 0 | if (_current_reconnect_ivl == -1) |
92 | 0 | candidate_interval = options.reconnect_ivl; |
93 | 0 | else if (_current_reconnect_ivl > std::numeric_limits<int>::max () / 2) |
94 | 0 | candidate_interval = std::numeric_limits<int>::max (); |
95 | 0 | else |
96 | 0 | candidate_interval = _current_reconnect_ivl * 2; |
97 | |
|
98 | 0 | if (candidate_interval > options.reconnect_ivl_max) |
99 | 0 | _current_reconnect_ivl = options.reconnect_ivl_max; |
100 | 0 | else |
101 | 0 | _current_reconnect_ivl = candidate_interval; |
102 | 0 | return _current_reconnect_ivl; |
103 | 0 | } else { |
104 | 0 | if (_current_reconnect_ivl == -1) |
105 | 0 | _current_reconnect_ivl = options.reconnect_ivl; |
106 | | // The new interval is the base interval + random value. |
107 | 0 | const int random_jitter = generate_random () % options.reconnect_ivl; |
108 | 0 | const int interval = |
109 | 0 | _current_reconnect_ivl |
110 | 0 | < std::numeric_limits<int>::max () - random_jitter |
111 | 0 | ? _current_reconnect_ivl + random_jitter |
112 | 0 | : std::numeric_limits<int>::max (); |
113 | 0 | return interval; |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | void zmq::stream_connecter_base_t::rm_handle () |
118 | 0 | { |
119 | 0 | rm_fd (_handle); |
120 | 0 | _handle = static_cast<handle_t> (NULL); |
121 | 0 | } |
122 | | |
123 | | void zmq::stream_connecter_base_t::close () |
124 | 0 | { |
125 | | // TODO before, this was an assertion for _s != retired_fd, but this does not match usage of close |
126 | 0 | if (_s != retired_fd) { |
127 | | #ifdef ZMQ_HAVE_WINDOWS |
128 | | const int rc = closesocket (_s); |
129 | | wsa_assert (rc != SOCKET_ERROR); |
130 | | #else |
131 | 0 | const int rc = ::close (_s); |
132 | 0 | errno_assert (rc == 0); |
133 | 0 | #endif |
134 | 0 | _socket->event_closed ( |
135 | 0 | make_unconnected_connect_endpoint_pair (_endpoint), _s); |
136 | 0 | _s = retired_fd; |
137 | 0 | } |
138 | 0 | } |
139 | | |
140 | | void zmq::stream_connecter_base_t::in_event () |
141 | 0 | { |
142 | | // We are not polling for incoming data, so we are actually called |
143 | | // because of error here. However, we can get error on out event as well |
144 | | // on some platforms, so we'll simply handle both events in the same way. |
145 | 0 | out_event (); |
146 | 0 | } |
147 | | |
148 | | void zmq::stream_connecter_base_t::create_engine ( |
149 | | fd_t fd_, const std::string &local_address_) |
150 | 0 | { |
151 | 0 | const endpoint_uri_pair_t endpoint_pair (local_address_, _endpoint, |
152 | 0 | endpoint_type_connect); |
153 | | |
154 | | // Create the engine object for this connection. |
155 | 0 | i_engine *engine; |
156 | 0 | if (options.raw_socket) |
157 | 0 | engine = new (std::nothrow) raw_engine_t (fd_, options, endpoint_pair); |
158 | 0 | else |
159 | 0 | engine = new (std::nothrow) zmtp_engine_t (fd_, options, endpoint_pair); |
160 | 0 | alloc_assert (engine); |
161 | | |
162 | | // Attach the engine to the corresponding session object. |
163 | 0 | send_attach (_session, engine); |
164 | | |
165 | | // Shut the connecter down. |
166 | 0 | terminate (); |
167 | |
|
168 | 0 | _socket->event_connected (endpoint_pair, fd_); |
169 | 0 | } |
170 | | |
171 | | void zmq::stream_connecter_base_t::timer_event (int id_) |
172 | 0 | { |
173 | | zmq_assert (id_ == reconnect_timer_id); |
174 | 0 | _reconnect_timer_started = false; |
175 | 0 | start_connecting (); |
176 | 0 | } |