join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
async_acceptor.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_CORE_ASYNC_ACCEPTOR_HPP
26#define JOIN_CORE_ASYNC_ACCEPTOR_HPP
27
28// libjoin.
30#include <join/acceptor.hpp>
31#include <join/function.hpp>
32#include <join/proactor.hpp>
33#include <join/backoff.hpp>
34
35// C++.
36#include <system_error>
37#include <utility>
38
39namespace join
40{
44 template <class Protocol, class Proactor>
45 class BasicAsyncStreamAcceptor : public CompletionHandler
46 {
47 public:
49 using Endpoint = typename Protocol::Endpoint;
50 using Socket = typename Protocol::Socket;
53
59 : _proactor (&proactor)
60 {
61 }
62
68
75
81
88
93 {
94 close ();
95 }
96
103 int create (const Endpoint& endpoint, int flags = SOCK_CLOEXEC | SOCK_NONBLOCK) noexcept
104 {
105 return _acceptor.create (endpoint, flags | SOCK_NONBLOCK);
106 }
107
111 void close () noexcept
112 {
113 Backoff backoff;
114
115 do
116 {
117 cancel ();
118
119 backoff ();
120 }
121 while (!_proactor->isProactorThread () && pending (_acceptOp.op));
122
123 _acceptor.close ();
124 }
125
133 ssize_t asyncAccept (AcceptHandler handler, int flags = SOCK_NONBLOCK | SOCK_CLOEXEC,
134 bool flush = true) noexcept
135 {
136 if (JOIN_UNLIKELY (!_acceptor.opened ()))
137 {
139 return -1;
140 }
141
142 if (JOIN_UNLIKELY (!armOp ()))
143 {
144 lastError = make_error_code (Errc::InUse);
145 return -1;
146 }
147
148 _acceptOp.remoteLen = sizeof (struct sockaddr_storage);
149 _acceptOp.acceptHandler = std::move (handler);
150 _acceptOp.op = IoOperation::makeAccept (_acceptor.handle (), _acceptOp.remote.addr (), &_acceptOp.remoteLen,
151 flags | SOCK_NONBLOCK, this);
152
153 if (_proactor->submit (_acceptOp.op, flush, false) == -1)
154 {
155 // LCOV_EXCL_START
156 _acceptOp.acceptHandler.reset ();
158 return -1;
159 // LCOV_EXCL_STOP
160 }
161
162 return 0;
163 }
164
172 ssize_t asyncAcceptMulti (AcceptHandler handler, int flags = SOCK_NONBLOCK | SOCK_CLOEXEC,
173 bool flush = true) noexcept
174 {
175 if (JOIN_UNLIKELY (!_acceptor.opened ()))
176 {
178 return -1;
179 }
180
181 if (JOIN_UNLIKELY (!armOp ()))
182 {
183 lastError = make_error_code (Errc::InUse);
184 return -1;
185 }
186
187 _acceptOp.remote = Endpoint ();
188 _acceptOp.acceptHandler = std::move (handler);
189 _acceptOp.op = IoOperation::makeAcceptMulti (_acceptor.handle (), flags | SOCK_NONBLOCK, this);
190
191 if (_proactor->submit (_acceptOp.op, flush, false) == -1)
192 {
193 // LCOV_EXCL_START
194 _acceptOp.acceptHandler.reset ();
196 return -1;
197 // LCOV_EXCL_STOP
198 }
199
200 return 0;
201 }
202
207 int cancel () noexcept
208 {
209 if (!inFlight (_acceptOp.op))
210 {
211 return 0;
212 }
213
214 if (_proactor->cancel (_acceptOp.op, true, true) == -1)
215 {
216 return (lastError == Errc::OperationFailed) ? 0 : -1;
217 }
218
219 return 0;
220 }
221
222#ifdef JOIN_HAS_IO_URING
227 int flush () noexcept
228 {
229 return _proactor->flush (false);
230 }
231#endif
232
238 {
239 return _acceptor.localEndpoint ();
240 }
241
246 bool opened () const noexcept
247 {
248 return _acceptor.opened ();
249 }
250
255 int family () const noexcept
256 {
257 return _acceptor.family ();
258 }
259
264 int type () const noexcept
265 {
266 return _acceptor.type ();
267 }
268
273 int protocol () const noexcept
274 {
275 return _acceptor.protocol ();
276 }
277
282 int handle () const noexcept
283 {
284 return _acceptor.handle ();
285 }
286
287 protected:
293 void onComplete (IoOperation& op, int result) override
294 {
295 std::error_code code =
296 (result < 0) ? std::error_code (-result, std::generic_category ()) : std::error_code ();
297
298 dispatch (op, code, (result > 0) ? static_cast<size_t> (result) : 0);
299 }
300
306 void onCancel (IoOperation& op, [[maybe_unused]] int result) override
307 {
308 dispatch (op, make_error_code (std::errc::operation_canceled), 0);
309 }
310
317 virtual void dispatch (IoOperation& op, const std::error_code& code, size_t size) noexcept
318 {
319 completeAccept (reinterpret_cast<AsyncAccept*> (&op), code, size);
320 }
321
328 void completeAccept (AsyncAccept* accept, const std::error_code& code, size_t handle) noexcept
329 {
330 Socket sock = code ? Socket () : Socket (static_cast<int> (handle), accept->remote);
331
332 if (accept->op.more)
333 {
334 if (JOIN_LIKELY (accept->acceptHandler))
335 {
336 accept->acceptHandler (std::move (sock), code, true);
337 }
338
339 return;
340 }
341
342 AcceptHandler handler = std::move (accept->acceptHandler);
343
344 if (JOIN_LIKELY (handler))
345 {
346 handler (std::move (sock), code, false);
347 }
348
350 }
351
356 bool armOp () noexcept
357 {
359
360 return _acceptOp.op.state.compare_exchange_strong (expected, IoOperation::State::Submitted,
361 std::memory_order_acquire, std::memory_order_relaxed) ||
362 (expected == IoOperation::State::Busy);
363 }
364
369 void disarmOp (IoOperation::State expected) noexcept
370 {
371 _acceptOp.op.state.compare_exchange_strong (expected, IoOperation::State::Idle, std::memory_order_release,
372 std::memory_order_relaxed);
373 }
374
380 bool inFlight (const IoOperation& op) const noexcept
381 {
382 return op.state.load (std::memory_order_acquire) == IoOperation::State::Submitted;
383 }
384
390 bool pending (const IoOperation& op) const noexcept
391 {
392 IoOperation::State state = op.state.load (std::memory_order_acquire);
393
394 return (state == IoOperation::State::Submitted) || (state == IoOperation::State::Busy);
395 }
396
397 private:
399 Proactor* _proactor;
400
402 Acceptor _acceptor;
403
405 AsyncAccept _acceptOp;
406 };
407}
408
409#endif
adaptive backoff strategy for busy-wait loops.
Definition backoff.hpp:43
asynchronous stream acceptor class.
Definition protocol.hpp:94
void completeAccept(AsyncAccept *accept, const std::error_code &code, size_t handle) noexcept
invoke the accept completion handler.
Definition async_acceptor.hpp:328
BasicAsyncStreamAcceptor & operator=(const BasicAsyncStreamAcceptor &other)=delete
copy assignment operator.
BasicStreamAcceptor< Protocol > Acceptor
Definition async_acceptor.hpp:48
int cancel() noexcept
cancel the acceptation in flight, if any.
Definition async_acceptor.hpp:207
int protocol() const noexcept
get acceptor protocol.
Definition async_acceptor.hpp:273
void onComplete(IoOperation &op, int result) override
method called when an operation completes.
Definition async_acceptor.hpp:293
ssize_t asyncAcceptMulti(AcceptHandler handler, int flags=SOCK_NONBLOCK|SOCK_CLOEXEC, bool flush=true) noexcept
start an asynchronous multishot acceptation, staying armed until cancelled or failed.
Definition async_acceptor.hpp:172
ssize_t asyncAccept(AcceptHandler handler, int flags=SOCK_NONBLOCK|SOCK_CLOEXEC, bool flush=true) noexcept
start an asynchronous acceptation.
Definition async_acceptor.hpp:133
typename Protocol::Endpoint Endpoint
Definition async_acceptor.hpp:49
int family() const noexcept
get address family.
Definition async_acceptor.hpp:255
bool opened() const noexcept
check if the acceptor is opened.
Definition async_acceptor.hpp:246
Endpoint localEndpoint() const
determine the local endpoint associated with this acceptor.
Definition async_acceptor.hpp:237
int create(const Endpoint &endpoint, int flags=SOCK_CLOEXEC|SOCK_NONBLOCK) noexcept
create acceptor.
Definition async_acceptor.hpp:103
BasicAsyncStreamAcceptor(const BasicAsyncStreamAcceptor &other)=delete
copy constructor.
~BasicAsyncStreamAcceptor()
destroy the acceptor instance.
Definition async_acceptor.hpp:92
int handle() const noexcept
get acceptor native handle.
Definition async_acceptor.hpp:282
bool armOp() noexcept
reserve the accept operation for submission.
Definition async_acceptor.hpp:356
void disarmOp(IoOperation::State expected) noexcept
release the accept operation reservation.
Definition async_acceptor.hpp:369
bool pending(const IoOperation &op) const noexcept
check if an operation is in flight or completing.
Definition async_acceptor.hpp:390
BasicAsyncStreamAcceptor(BasicAsyncStreamAcceptor &&other)=delete
move constructor.
BasicAsyncStreamAcceptor(Proactor &proactor=ProactorThread::proactor())
create the acceptor instance.
Definition async_acceptor.hpp:58
int type() const noexcept
get the acceptor communication semantic.
Definition async_acceptor.hpp:264
bool inFlight(const IoOperation &op) const noexcept
check if an operation is in flight.
Definition async_acceptor.hpp:380
typename Protocol::Socket Socket
Definition async_acceptor.hpp:50
typename AsyncAccept::Accept AcceptHandler
Definition async_acceptor.hpp:52
BasicAsyncAccept< Protocol, Proactor > AsyncAccept
Definition async_acceptor.hpp:51
void onCancel(IoOperation &op, int result) override
method called when an operation is cancelled.
Definition async_acceptor.hpp:306
void close() noexcept
close acceptor, cancelling the acceptation in flight.
Definition async_acceptor.hpp:111
virtual void dispatch(IoOperation &op, const std::error_code &code, size_t size) noexcept
invoke the completion handler of the given operation.
Definition async_acceptor.hpp:317
static BasicProactor & proactor()
get the Proactor instance owned by the singleton ProactorThread.
Definition proactor.hpp:982
basic proactor class.
Definition proactor.hpp:156
int submit(IoOperation &op, bool flush=false, bool sync=false) noexcept
submit an asynchronous operation to the proactor.
Definition proactor.hpp:655
bool isProactorThread() const noexcept
check if the calling thread is the proactor thread.
Definition proactor_epoll_impl.hpp:252
int cancel(IoOperation &op, bool flush=false, bool sync=false) noexcept
cancel an in-flight operation.
Definition proactor.hpp:703
basic stream acceptor class.
Definition protocol.hpp:53
bool opened() const noexcept
check if the socket is opened.
Definition acceptor.hpp:237
Endpoint localEndpoint() const
determine the local endpoint associated with this socket.
Definition acceptor.hpp:219
void close() noexcept
close acceptor.
Definition acceptor.hpp:172
int family() const noexcept
get address family.
Definition acceptor.hpp:246
int protocol() const noexcept
get acceptor protocol.
Definition acceptor.hpp:264
int type() const noexcept
get the protocol communication semantic.
Definition acceptor.hpp:255
int handle() const noexcept
get socket native handle.
Definition acceptor.hpp:273
int create(const Endpoint &endpoint, int flags=SOCK_CLOEXEC) noexcept
create acceptor
Definition acceptor.hpp:106
Definition acceptor.hpp:32
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
asynchronous accept operation.
Definition async_operation.hpp:64
Function< void(Socket &&, const std::error_code &, bool), 16 > Accept
handler invoked on completion.
Definition async_operation.hpp:69
Accept acceptHandler
handler invoked on completion.
Definition async_operation.hpp:75
Endpoint remote
remote endpoint.
Definition async_operation.hpp:78
socklen_t remoteLen
remote address length.
Definition async_operation.hpp:81
IoOperation op
operation submitted to the proactor.
Definition async_operation.hpp:72
Describes a single asynchronous operation submitted to the Proactor.
Definition io_operation.hpp:47
static IoOperation makeAccept(int fd, sockaddr *addr, socklen_t *addrlen, int flags, CompletionHandler *handler) noexcept
build an accept operation.
Definition io_operation.cpp:102
State
operation lifecycle state.
Definition io_operation.hpp:52
static IoOperation makeAcceptMulti(int fd, int flags, CompletionHandler *handler) noexcept
build a multishot accept operation.
Definition io_operation.cpp:119
std::atomic< State > state
operation state.
Definition io_operation.hpp:392
#define JOIN_LIKELY(x)
Definition utils.hpp:45
#define JOIN_UNLIKELY(x)
Definition utils.hpp:46