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/*
21 * MIT License
22 *
23 * Permission is hereby granted, free of charge, to any person obtaining a copy
24 * of this software and associated documentation files (the "Software"), to deal
25 * in the Software without restriction, including without limitation the rights
26 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27 * copies of the Software, and to permit persons to whom the Software is
28 * furnished to do so, subject to the following conditions:
29 *
30 * The above copyright notice and this permission notice shall be included in
31 * all copies or substantial portions of the Software.
32 *
33 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39 * THE SOFTWARE.
40 */
41
42#include "core/State.h"
43#include "core/socket/stream/SocketConnector.h"
44
45#ifndef DOXYGEN_SHOULD_SKIP_THIS
46
47#include "log/Logger.h"
48#include "utils/PreserveErrno.h"
49
50#include <iomanip>
51#include <string>
52#include <utility>
53
54#endif // DOXYGEN_SHOULD_SKIP_THIS
55
56namespace core::socket::stream {
57
58 template <typename SocketAddress, typename PhysicalSocket, typename Config>
59 SocketAddress getLocalSocketAddress(PhysicalSocket& physicalSocket, Config& config) {
60 typename SocketAddress::SockAddr localSockAddr;
61 typename SocketAddress::SockLen localSockAddrLen = sizeof(typename SocketAddress::SockAddr);
62
63 SocketAddress localPeerAddress;
64 if (physicalSocket.getSockName(localSockAddr, localSockAddrLen) == 0) {
65 try {
66 localPeerAddress = config->Local::getSocketAddress(localSockAddr, localSockAddrLen);
67 LOG(TRACE) << config->getInstanceName() << " [" << physicalSocket.getFd() << "]" << std::setw(25)
68 << " PeerAddress (local): " << localPeerAddress.toString();
69 } catch (const typename SocketAddress::BadSocketAddress& badSocketAddress) {
70 LOG(WARNING) << config->getInstanceName() << " [" << physicalSocket.getFd() << "]" << std::setw(25)
71 << " PeerAddress (local): " << badSocketAddress.what();
72 }
73 } else {
74 PLOG(WARNING) << config->getInstanceName() << " [" << physicalSocket.getFd() << "]" << std::setw(25)
75 << " PeerAddress (local) not retrievable";
76 }
77
78 return localPeerAddress;
79 }
80
81 template <typename SocketAddress, typename PhysicalSocket, typename Config>
82 SocketAddress getRemoteSocketAddress(PhysicalSocket& physicalSocket, Config& config) {
83 typename SocketAddress::SockAddr remoteSockAddr;
84 typename SocketAddress::SockLen remoteSockAddrLen = sizeof(typename SocketAddress::SockAddr);
85
86 SocketAddress remotePeerAddress;
87 if (physicalSocket.getPeerName(remoteSockAddr, remoteSockAddrLen) == 0) {
88 try {
89 remotePeerAddress = config->Remote::getSocketAddress(remoteSockAddr, remoteSockAddrLen);
90 LOG(TRACE) << config->getInstanceName() << " [" << physicalSocket.getFd() << "]" << std::setw(25)
91 << " PeerAddress (remote): " << remotePeerAddress.toString();
92 } catch (const typename SocketAddress::BadSocketAddress& badSocketAddress) {
93 LOG(WARNING) << config->getInstanceName() << " [" << physicalSocket.getFd() << "]" << std::setw(25)
94 << " PeerAddress (remote): " << badSocketAddress.what();
95 }
96 } else {
97 PLOG(WARNING) << config->getInstanceName() << " [" << physicalSocket.getFd() << "]" << std::setw(25)
98 << " PeerAddress (remote) not retrievable";
99 }
100
101 return remotePeerAddress;
102 }
103
104 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
127
128 template <typename PhysicalSocketServer, typename Config, template <typename PhysicalSocketServerT> typename SocketConnection>
145
146 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
149
150 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
152 if (!config->getDisabled()) {
153 try {
154 LOG(TRACE) << config->getInstanceName() << " Starting";
155
158
159 try {
161
163 switch (errno) {
164 case EMFILE:
165 case ENFILE:
166 case ENOBUFS:
167 case ENOMEM:
168 PLOG(DEBUG) << config->getInstanceName() << " open: '" << localAddress.toString() << "'";
169
171 break;
172 default:
173 PLOG(DEBUG) << config->getInstanceName() << " open: '" << localAddress.toString() << "'";
174
176 break;
177 }
178
180 } else if (physicalClientSocket.bind(localAddress) < 0) {
181 switch (errno) {
182 case EADDRINUSE:
183 PLOG(DEBUG) << config->getInstanceName() << " bind: '" << localAddress.toString() << "'";
184
186 break;
187 default:
188 PLOG(DEBUG) << config->getInstanceName() << " bind: '" << localAddress.toString() << "'";
189
191 break;
192 }
193
196 switch (errno) {
197 case EADDRINUSE:
198 case EADDRNOTAVAIL:
199 case ECONNREFUSED:
200 case ENETUNREACH:
201 case ENOENT:
202 case EHOSTDOWN:
203 PLOG(DEBUG) << config->getInstanceName() << " connect: '" << remoteAddress.toString() << "'";
204
206 break;
207 default:
208 PLOG(DEBUG) << config->getInstanceName() << " connect: '" << remoteAddress.toString() << "'";
209
211 break;
212 }
213
215 if (remoteAddress.useNext()) {
217
218 LOG(DEBUG) << config->getInstanceName() << " using next SocketAddress: '"
219 << config->Remote::getSocketAddress().toString() << "'";
220
222 } else {
224 }
225 } else if (PhysicalClientSocket::connectInProgress(errno)) {
227 LOG(DEBUG) << config->getInstanceName() << " connect in progress: '" << remoteAddress.toString() << "'";
228 } else {
229 LOG(DEBUG) << config->getInstanceName() << " not enabled: '" << remoteAddress.toString() << "'";
230
231 state = core::socket::STATE(core::socket::STATE_FATAL, ECANCELED, "SocketConnector not enabled");
232
234 }
235 } else {
236 LOG(DEBUG) << config->getInstanceName() << " [" << physicalClientSocket.getFd() << "] connect success: '"
237 << remoteAddress.toString() << "'";
238
240
245 remoteAddress.toString(false),
253
256 }
257 } catch (const typename SocketAddress::BadSocketAddress& badSocketAddress) {
258 LOG(DEBUG) << config->getInstanceName() << " " << badSocketAddress.what();
259
261 }
262 } catch (const typename SocketAddress::BadSocketAddress& badSocketAddress) {
263 LOG(DEBUG) << config->getInstanceName() << " " << badSocketAddress.what();
264
266 }
267 } else {
268 LOG(DEBUG) << config->getInstanceName() << " disabled";
269
271 }
272
273 if (isEnabled()) {
275 } else {
276 destruct();
277 }
278 }
279
280 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
282 int cErrno = 0;
283
284 if (physicalClientSocket.getSockError(cErrno) == 0) { // == 0->return valid : < 0->getsockopt failed
285 const utils::PreserveErrno pe(cErrno); // errno = cErrno
286
287 if (errno == 0) {
288 LOG(DEBUG) << config->getInstanceName() << " [" << physicalClientSocket.getFd() << "] connect success: '"
289 << remoteAddress.toString() << "'";
290
292
297 remoteAddress.toString(false),
305
308
309 disable();
310 } else if (PhysicalClientSocket::connectInProgress(errno)) {
311 LOG(TRACE) << config->getInstanceName() << " connect still in progress: '" << remoteAddress.toString() << "'";
312 } else {
314 if (remoteAddress.useNext()) {
316
317 switch (errno) {
318 case EADDRINUSE:
319 case EADDRNOTAVAIL:
320 case ECONNREFUSED:
321 case ENETUNREACH:
322 case ENOENT:
323 case EHOSTDOWN:
324 PLOG(DEBUG) << config->getInstanceName() << " connect: '" << remoteAddress.toString() << "'";
325
327 break;
328 default:
329 PLOG(DEBUG) << config->getInstanceName() << ": connect: '" << remoteAddress.toString() << "'";
330
332 break;
333 }
334
336
337 LOG(DEBUG) << config->getInstanceName() << " using next SocketAddress: '"
338 << config->Remote::getSocketAddress().toString() << "'";
339
341
342 disable();
343 } else {
345
346 switch (errno) {
347 case EADDRINUSE:
348 case EADDRNOTAVAIL:
349 case ECONNREFUSED:
350 case ENETUNREACH:
351 case ENOENT:
352 case EHOSTDOWN:
353 PLOG(DEBUG) << config->getInstanceName() << " connect: '" << remoteAddress.toString() << "'";
354
356 break;
357 default:
358 PLOG(DEBUG) << config->getInstanceName() << " connect: '" << remoteAddress.toString() << "'";
359
361 break;
362 }
363
365
366 disable();
367 }
368 }
369 } else {
370 PLOG(DEBUG) << config->getInstanceName() << " getsockopt syscall error: '" << remoteAddress.toString() << "'";
371
373 disable();
374 }
375 }
376
377 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
381
382 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
384 LOG(TRACE) << config->getInstanceName() << " connect timeout " << remoteAddress.toString();
385
387 if (remoteAddress.useNext()) {
388 LOG(DEBUG) << config->getInstanceName() << " using next SocketAddress: '" << config->Remote::getSocketAddress().toString()
389 << "'";
390
392 } else {
393 LOG(DEBUG) << config->getInstanceName() << " connect timeout '" << remoteAddress.toString() << "'";
394 errno = ETIMEDOUT;
395
397 }
398
400 }
401
402 template <typename PhysicalSocketClient, typename Config, template <typename PhysicalSocketClientT> typename SocketConnection>
406
407} // namespace core::socket::stream
virtual ~Socket()
Definition Socket.hpp:56
Config & getConfig() const
Definition Socket.hpp:60
std::shared_ptr< Config > config
Definition Socket.h:72
Socket(const std::string &name)
Definition Socket.hpp:51
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:59