SNode.C
Loading...
Searching...
No Matches
SocketAcceptor.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, 2026
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/SocketAcceptor.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 PhysicalSocketServer,
59 typename Config,
60 template <typename ConfigT, typename PhysicalSocketServerT> typename SocketConnection>
61 SocketAcceptor<PhysicalSocketServer, Config, SocketConnection>::SocketAcceptor(
62 const std::function<void(SocketConnection*)>& onConnect,
63 const std::function<void(SocketConnection*)>& onConnected,
64 const std::function<void(SocketConnection*)>& onDisconnect,
65 const std::function<void(core::eventreceiver::AcceptEventReceiver*)>& onInitState,
66 const std::function<void(const SocketAddress&, core::socket::State)>& onStatus,
67 const std::shared_ptr<Config>& config)
68 : core::eventreceiver::AcceptEventReceiver(config->getInstanceName() + " SocketAcceptor", 0)
69 , onConnect(onConnect)
70 , onConnected(onConnected)
71 , onDisconnect(onDisconnect)
72 , onInitState(onInitState)
73 , onStatus(onStatus)
74 , config(config) {
75 }
76
77 template <typename PhysicalSocketServer,
78 typename Config,
79 template <typename ConfigT, typename PhysicalSocketServerT> typename SocketConnection>
80 SocketAcceptor<PhysicalSocketServer, Config, SocketConnection>::SocketAcceptor(const SocketAcceptor& socketAcceptor)
81 : core::eventreceiver::AcceptEventReceiver(socketAcceptor.config->getInstanceName() + " SocketAcceptor", 0)
82 , onConnect(socketAcceptor.onConnect)
83 , onConnected(socketAcceptor.onConnected)
84 , onDisconnect(socketAcceptor.onDisconnect)
85 , onInitState(socketAcceptor.onInitState)
86 , onStatus(socketAcceptor.onStatus)
87 , config(socketAcceptor.config) {
88 }
89
90 template <typename PhysicalSocketServer,
91 typename Config,
92 template <typename ConfigT, typename PhysicalSocketServerT> typename SocketConnection>
93 SocketAcceptor<PhysicalSocketServer, Config, SocketConnection>::~SocketAcceptor() {
94 }
95
96 template <typename PhysicalSocketServer,
97 typename Config,
98 template <typename ConfigT, typename PhysicalSocketServerT> typename SocketConnection>
99 void SocketAcceptor<PhysicalSocketServer, Config, SocketConnection>::init() {
100 if (!config->getDisabled()) {
101 try {
102 core::socket::State state = core::socket::STATE_OK;
103
104 LOG(DEBUG) << config->getInstanceName() << " Listen: starting";
105
106 bindAddress = config->Local::getSocketAddress();
107
108 if (physicalServerSocket.open(config->getSocketOptions(), PhysicalServerSocket::Flags::NONBLOCK) < 0) {
109 PLOG(ERROR) << config->getInstanceName() << " open " << bindAddress.toString();
110
111 switch (errno) {
112 case EMFILE:
113 case ENFILE:
114 case ENOBUFS:
115 case ENOMEM:
116 state = core::socket::STATE_ERROR;
117 break;
118 default:
119 state = core::socket::STATE_FATAL;
120 break;
121 }
122 } else {
123 LOG(DEBUG) << config->getInstanceName() << " open " << bindAddress.toString() << ": success";
124
125 if (physicalServerSocket.bind(bindAddress) < 0) {
126 PLOG(ERROR) << config->getInstanceName() << " bind " << bindAddress.toString();
127
128 switch (errno) {
129 case EADDRINUSE:
130
131 state = core::socket::STATE_ERROR;
132 break;
133 default:
134
135 state = core::socket::STATE_FATAL;
136 break;
137 }
138 } else {
139 LOG(DEBUG) << config->getInstanceName() << " bind " << bindAddress.toString() << ": success";
140
141 if (physicalServerSocket.listen(config->getBacklog()) < 0) {
142 PLOG(ERROR) << config->getInstanceName() << " listen " << bindAddress.toString();
143
144 switch (errno) {
145 case EADDRINUSE:
146 state = core::socket::STATE_ERROR;
147 break;
148 default:
149 state = core::socket::STATE_FATAL;
150 break;
151 }
152 } else {
153 LOG(DEBUG) << config->getInstanceName() << " listen " << bindAddress.toString() << ": success";
154
155 if (enable(physicalServerSocket.getFd())) {
156 LOG(DEBUG) << config->getInstanceName() << " enable " << bindAddress.toString() << ": success";
157 } else {
158 LOG(ERROR) << config->getInstanceName() << " enable " << bindAddress.toString()
159 << ": failed. No valid descriptor created";
160
161 state = core::socket::STATE(core::socket::STATE_FATAL, ECANCELED, "SocketAcceptor not enabled");
162 }
163 }
164 }
165 }
166
167 SocketAddress currentLocalAddress = bindAddress;
168 if (bindAddress.useNext()) {
169 onStatus(currentLocalAddress, (state | core::socket::State::NO_RETRY));
170
171 LOG(INFO) << config->getInstanceName()
172 << ": Using next SocketAddress: " << config->Local::getSocketAddress().toString();
173
175 } else {
176 onStatus(currentLocalAddress, state);
177 }
178 } catch (const typename SocketAddress::BadSocketAddress& badSocketAddress) {
179 core::socket::State state =
180 core::socket::STATE(badSocketAddress.getState(), badSocketAddress.getErrnum(), badSocketAddress.what());
181
182 LOG(ERROR) << state.what();
183
184 onStatus({}, state);
185 }
186 } else {
187 LOG(DEBUG) << config->getInstanceName() << ": disabled";
188
189 onStatus({}, core::socket::STATE_DISABLED);
190 }
191
192 if (isEnabled()) {
193 onInitState(this);
195 } else {
197 }
198 }
199
200 template <typename PhysicalSocketServer,
201 typename Config,
202 template <typename ConfigT, typename PhysicalSocketServerT> typename SocketConnection>
203 void SocketAcceptor<PhysicalSocketServer, Config, SocketConnection>::acceptEvent() {
204 if (isEnabled()) {
205 int acceptsPerTick = config->getAcceptsPerTick();
206
207 do {
208 PhysicalServerSocket connectedPhysicalSocket(physicalServerSocket.accept4(PhysicalServerSocket::Flags::NONBLOCK),
210
211 if (connectedPhysicalSocket.isValid()) {
212 SocketConnection* socketConnection = new SocketConnection(std::move(connectedPhysicalSocket), onDisconnect, config);
213
214 LOG(DEBUG) << config->getInstanceName() << " accept " << bindAddress.toString() << ": success";
215 LOG(DEBUG) << " " << socketConnection->getRemoteAddress().toString() << " -> "
216 << socketConnection->getLocalAddress().toString();
217
218 onConnect(socketConnection);
219 onConnected(socketConnection);
220 } else if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
221 PLOG(WARNING) << config->getInstanceName() << " accept " << bindAddress.toString();
222 }
223 } while (--acceptsPerTick > 0);
224 }
225 }
226
227 template <typename PhysicalSocketServer,
228 typename Config,
229 template <typename ConfigT, typename PhysicalSocketServerT> typename SocketConnection>
230 void SocketAcceptor<PhysicalSocketServer, Config, SocketConnection>::unobservedEvent() {
232 }
233
234 template <typename PhysicalSocketServer,
235 typename Config,
236 template <typename ConfigT, typename PhysicalSocketServerT> typename SocketConnection>
237 void SocketAcceptor<PhysicalSocketServer, Config, SocketConnection>::destruct() {
238 if (!config->getDisabled()) {
239 onInitState(this);
240 }
241
242 delete this;
243 }
244
245} // namespace core::socket::stream
void setTimeout(const utils::Timeval &timeout)
std::string what() const
Definition State.cpp:114
static constexpr int NO_RETRY
Definition State.h:59
State operator|(int state)
Definition State.cpp:102
std::function< void(SocketConnection *)> onConnected
SocketConnectionT< PhysicalServerSocket, Config > SocketConnection
PhysicalSocketServerT PhysicalServerSocket
SocketAcceptor(const SocketAcceptor &socketAcceptor)
SocketAcceptor(const std::function< void(SocketConnection *)> &onConnect, const std::function< void(SocketConnection *)> &onConnected, const std::function< void(SocketConnection *)> &onDisconnect, const std::function< void(core::eventreceiver::AcceptEventReceiver *)> &onInitState, const std::function< void(const SocketAddress &, core::socket::State)> &onStatus, const std::shared_ptr< Config > &config)
std::function< void(SocketConnection *)> onConnect
std::function< void(SocketConnection *)> onDisconnect
std::shared_ptr< Config > config
typename PhysicalServerSocket::SocketAddress SocketAddress
PhysicalServerSocket physicalServerSocket
std::function< void(core::eventreceiver::AcceptEventReceiver *)> onInitState
std::function< void(const SocketAddress &, core::socket::State)> onStatus
SocketAcceptor(const std::shared_ptr< core::socket::stream::SocketContextFactory > &socketContextFactory, const std::function< void(SocketConnection *)> &onConnect, const std::function< void(SocketConnection *)> &onConnected, const std::function< void(SocketConnection *)> &onDisconnect, const std::function< void(core::eventreceiver::AcceptEventReceiver *)> &onInitState, const std::function< void(const SocketAddress &, core::socket::State)> &onStatus, const std::shared_ptr< Config > &config)
typename Super::SocketAddress SocketAddress
typename Super::SocketConnection SocketConnection
core::socket::stream::SocketAcceptor< PhysicalServerSocketT, ConfigT, core::socket::stream::legacy::SocketConnection > Super
SocketAcceptor(const SocketAcceptor &socketAcceptor)
State
Definition State.h:51
@ RUNNING
Definition State.h:51
State eventLoopState()
Definition State.cpp:52