SNode.C
Loading...
Searching...
No Matches
SocketConnector.hpp
Go to the documentation of this file.
1/*
2 * SNode.C - a slim toolkit for network communication
3 * Copyright (C) Volker Christian <me@vchrist.at>
4 * 2020, 2021, 2022, 2023, 2024, 2025
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "core/State.h"
21#include "core/socket/stream/SocketConnector.h"
22
23#ifndef DOXYGEN_SHOULD_SKIP_THIS
24
25#include "log/Logger.h"
26#include "utils/PreserveErrno.h"
27
28#include <iomanip>
29#include <string>
30#include <utility>
31
32#endif // DOXYGEN_SHOULD_SKIP_THIS
33
34namespace core::socket::stream {
35
36 template <typename SocketAddress, typename PhysicalSocket, typename Config>
37 SocketAddress getLocalSocketAddress(PhysicalSocket& physicalSocket, Config& config) {
38 typename SocketAddress::SockAddr localSockAddr;
39 typename SocketAddress::SockLen localSockAddrLen = sizeof(typename SocketAddress::SockAddr);
40
41 SocketAddress localPeerAddress;
42 if (physicalSocket.getSockName(localSockAddr, localSockAddrLen) == 0) {
43 try {
44 localPeerAddress = config->Local::getSocketAddress(localSockAddr, localSockAddrLen);
45 LOG(TRACE) << config->getInstanceName() << " [" << physicalSocket.getFd() << "]" << std::setw(25)
46 << " PeerAddress (local): " << localPeerAddress.toString();
47 } catch (const typename SocketAddress::BadSocketAddress& badSocketAddress) {
48 LOG(WARNING) << config->getInstanceName() << " [" << physicalSocket.getFd() << "]" << std::setw(25)
49 << " PeerAddress (local): " << badSocketAddress.what();
50 }
51 } else {
52 PLOG(WARNING) << config->getInstanceName() << " [" << physicalSocket.getFd() << "]" << std::setw(25)
53 << " PeerAddress (local) not retrievable";
54 }
55
56 return localPeerAddress;
57 }
58
59 template <typename SocketAddress, typename PhysicalSocket, typename Config>
60 SocketAddress getRemoteSocketAddress(PhysicalSocket& physicalSocket, Config& config) {
61 typename SocketAddress::SockAddr remoteSockAddr;
62 typename SocketAddress::SockLen remoteSockAddrLen = sizeof(typename SocketAddress::SockAddr);
63
64 SocketAddress remotePeerAddress;
65 if (physicalSocket.getPeerName(remoteSockAddr, remoteSockAddrLen) == 0) {
66 try {
67 remotePeerAddress = config->Remote::getSocketAddress(remoteSockAddr, remoteSockAddrLen);
68 LOG(TRACE) << config->getInstanceName() << " [" << physicalSocket.getFd() << "]" << std::setw(25)
69 << " PeerAddress (remote): " << remotePeerAddress.toString();
70 } catch (const typename SocketAddress::BadSocketAddress& badSocketAddress) {
71 LOG(WARNING) << config->getInstanceName() << " [" << physicalSocket.getFd() << "]" << std::setw(25)
72 << " PeerAddress (remote): " << badSocketAddress.what();
73 }
74 } else {
75 PLOG(WARNING) << config->getInstanceName() << " [" << physicalSocket.getFd() << "]" << std::setw(25)
76 << " PeerAddress (remote) not retrievable";
77 }
78
79 return remotePeerAddress;
80 }
81
82 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
101
102 template <typename PhysicalSocketServer, typename Config, template <typename PhysicalSocketServerT> typename SocketConnection>
115
116 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
119
120 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
123 try {
124 LOG(TRACE) << config->getInstanceName() << " Starting";
125
128
129 try {
131
133 switch (errno) {
134 case EMFILE:
135 case ENFILE:
136 case ENOBUFS:
137 case ENOMEM:
138 PLOG(DEBUG) << config->getInstanceName() << " open: '" << localAddress.toString() << "'";
139
141 break;
142 default:
143 PLOG(DEBUG) << config->getInstanceName() << " open: '" << localAddress.toString() << "'";
144
146 break;
147 }
148
150 } else if (physicalClientSocket.bind(localAddress) < 0) {
151 switch (errno) {
152 case EADDRINUSE:
153 PLOG(DEBUG) << config->getInstanceName() << " bind: '" << localAddress.toString() << "'";
154
156 break;
157 default:
158 PLOG(DEBUG) << config->getInstanceName() << " bind: '" << localAddress.toString() << "'";
159
161 break;
162 }
163
166 switch (errno) {
167 case EADDRINUSE:
168 case EADDRNOTAVAIL:
169 case ECONNREFUSED:
170 case ENETUNREACH:
171 case ENOENT:
172 case EHOSTDOWN:
173 PLOG(DEBUG) << config->getInstanceName() << " connect: '" << remoteAddress.toString() << "'";
174
176 break;
177 default:
178 PLOG(DEBUG) << config->getInstanceName() << " connect: '" << remoteAddress.toString() << "'";
179
181 break;
182 }
183
184 if (remoteAddress.useNext()) {
186
187 LOG(DEBUG) << config->getInstanceName() << " using next SocketAddress: '"
188 << config->Remote::getSocketAddress().toString() << "'";
189
191 } else {
193 }
194 } else if (PhysicalClientSocket::connectInProgress(errno)) {
196 LOG(DEBUG) << config->getInstanceName() << " connect in progress: '" << remoteAddress.toString() << "'";
197 } else {
198 LOG(DEBUG) << config->getInstanceName() << " not enabled: '" << remoteAddress.toString() << "'";
199
200 state = core::socket::STATE(core::socket::STATE_FATAL, ECANCELED, "SocketConnector not enabled");
201
203 }
204 } else {
205 LOG(DEBUG) << config->getInstanceName() << " [" << physicalClientSocket.getFd() << "] connect success: '"
206 << remoteAddress.toString() << "'";
207
209
214 remoteAddress.toString(false),
222
225 }
226 } catch (const typename SocketAddress::BadSocketAddress& badSocketAddress) {
227 LOG(DEBUG) << config->getInstanceName() << " " << badSocketAddress.what();
228
230 }
231 } catch (const typename SocketAddress::BadSocketAddress& badSocketAddress) {
232 LOG(DEBUG) << config->getInstanceName() << " " << badSocketAddress.what();
233
235 }
236 } else {
237 LOG(DEBUG) << config->getInstanceName() << " disabled";
238
240 }
241
242 if (isEnabled()) {
244 } else {
245 destruct();
246 }
247 }
248
249 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
251 int cErrno = 0;
252 if (physicalClientSocket.getSockError(cErrno) == 0) { // == 0->return valid : < 0->getsockopt failed
253 const utils::PreserveErrno pe(cErrno); // errno = cErrno
254
255 if (errno == 0) {
256 LOG(DEBUG) << config->getInstanceName() << " [" << physicalClientSocket.getFd() << "] connect success: '"
257 << remoteAddress.toString() << "'";
258
260
265 remoteAddress.toString(false),
273
276
277 disable();
278 } else if (PhysicalClientSocket::connectInProgress(errno)) {
279 LOG(TRACE) << config->getInstanceName() << " connect still in progress: '" << remoteAddress.toString() << "'";
280 } else if (remoteAddress.useNext()) {
282
283 switch (errno) {
284 case EADDRINUSE:
285 case EADDRNOTAVAIL:
286 case ECONNREFUSED:
287 case ENETUNREACH:
288 case ENOENT:
289 case EHOSTDOWN:
290 PLOG(DEBUG) << config->getInstanceName() << " connect: '" << remoteAddress.toString() << "'";
291
293 break;
294 default:
295 PLOG(DEBUG) << config->getInstanceName() << ": connect: '" << remoteAddress.toString() << "'";
296
298 break;
299 }
300
302
303 LOG(DEBUG) << config->getInstanceName() << " using next SocketAddress: '" << config->Remote::getSocketAddress().toString()
304 << "'";
305
307
308 disable();
309 } else {
311
312 switch (errno) {
313 case EADDRINUSE:
314 case EADDRNOTAVAIL:
315 case ECONNREFUSED:
316 case ENETUNREACH:
317 case ENOENT:
318 case EHOSTDOWN:
319 PLOG(DEBUG) << config->getInstanceName() << " connect: '" << remoteAddress.toString() << "'";
320
322 break;
323 default:
324 PLOG(DEBUG) << config->getInstanceName() << " connect: '" << remoteAddress.toString() << "'";
325
327 break;
328 }
329
331
332 disable();
333 }
334 } else {
335 PLOG(DEBUG) << config->getInstanceName() << " getsockopt syscall error: '" << remoteAddress.toString() << "'";
336
338 disable();
339 }
340 }
341
342 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
346
347 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
349 LOG(TRACE) << config->getInstanceName() << " connect timeout " << remoteAddress.toString();
350
351 if (remoteAddress.useNext()) {
352 LOG(DEBUG) << config->getInstanceName() << " using next SocketAddress: '" << config->Remote::getSocketAddress().toString()
353 << "'";
354
356 } else {
357 LOG(DEBUG) << config->getInstanceName() << " connect timeout '" << remoteAddress.toString() << "'";
358 errno = ETIMEDOUT;
359
361 }
362
364 }
365
366 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
370
371} // namespace core::socket::stream
virtual ~Socket()
Definition Socket.hpp:34
Config & getConfig() const
Definition Socket.hpp:38
std::shared_ptr< Config > config
Definition Socket.h:50
Socket(const std::string &name)
Definition Socket.hpp:29
void onReceivedFromPeer(std::size_t available) final
void setTimeout(const utils::Timeval &timeout) final
std::size_t readFromPeer(char *chunk, std::size_t chunkLen) final
const SocketAddress & getRemoteAddress() const final
void doWriteShutdown(const std::function< void()> &onShutdown) override
void shutdownWrite(bool forceClose) final
void sendToPeer(const char *chunk, std::size_t chunkLen) final
const SocketAddress & getLocalAddress() const final
SocketConnection(const std::string &instanceName, PhysicalSocket &&physicalSocket, const std::function< void(SocketConnection *)> &onDisconnect, const std::string &configuredServer, const SocketAddress &localAddress, const SocketAddress &remoteAddress, const utils::Timeval &readTimeout, const utils::Timeval &writeTimeout, std::size_t readBlockSize, std::size_t writeBlockSize, const utils::Timeval &terminateTimeout)
SocketConnector(const SocketConnector &socketConnector)
SocketAddress getRemoteSocketAddress(PhysicalSocket &physicalSocket, Config &config)
SocketAddress getLocalSocketAddress(PhysicalSocket &physicalSocket, Config &config)
Definition Config.h:37