join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
async_raw_socket.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_CORE_ASYNC_RAW_SOCKET_HPP
26#define JOIN_CORE_ASYNC_RAW_SOCKET_HPP
27
28// libjoin.
30#include <join/async_socket.hpp>
31#include <join/raw_socket.hpp>
32#include <join/function.hpp>
33#include <join/utils.hpp>
34
35// C++.
36#include <system_error>
37#include <utility>
38#include <string>
39
40// C.
41#include <cstddef>
42#include <cstring>
43
44namespace join
45{
49 template <class Protocol, class Proactor, size_t OpCount>
50 class BasicAsyncRawSocket : public BasicAsyncSocket<Protocol, Proactor, OpCount>
51 {
52 public:
53 using Socket = typename Protocol::Socket;
54 using Endpoint = typename Protocol::Endpoint;
55 using Option = typename Socket::Option;
58 using ReadHandler = typename AsyncRead::Read;
62
68 : BasicAsyncSocket<Protocol, Proactor, OpCount> (proactor)
69 {
70 }
71
78 : BasicAsyncSocket<Protocol, Proactor, OpCount> (std::move (sock), proactor)
79 {
80 }
81
87
94
101 {
102 this->resumeAll ();
103 }
104
111 {
113
114 this->resumeAll ();
115
116 return *this;
117 }
118
123 {
124 this->close ();
125 }
126
132 int bind (const Endpoint& endpoint) noexcept
133 {
134 return this->_socket.bind (endpoint);
135 }
136
142 int bindToDevice (const std::string& device) noexcept
143 {
144 return this->_socket.bindToDevice (device);
145 }
146
151 int canRead () const noexcept
152 {
153 return this->_socket.canRead ();
154 }
155
165 ssize_t asyncRead (char* data, size_t maxSize, ReadHandler handler, bool flush = true,
166 bool link = false) noexcept
167 {
168 if (JOIN_UNLIKELY (!this->_socket.opened ()))
169 {
171 return -1;
172 }
173
174 AsyncRead* read = allocateRead ();
175 if (JOIN_UNLIKELY (read == nullptr))
176 {
178 return -1;
179 }
180
181 read->readHandler = std::move (handler);
182 read->iov.iov_base = data;
183 read->iov.iov_len = maxSize;
184 read->msg.msg_name = nullptr;
185 read->msg.msg_namelen = 0;
186 read->msg.msg_iov = &read->iov;
187 read->msg.msg_iovlen = 1;
188 read->msg.msg_control = nullptr;
189 read->msg.msg_controllen = 0;
190 read->msg.msg_flags = 0;
191 read->op = IoOperation::makeRecvmsg (this->_socket.handle (), &read->msg, 0, this, link);
192 read->op.state.store (IoOperation::State::Submitted, std::memory_order_release);
193
194 size_t index = this->_arena.getIndex (read);
195
196 if (this->_proactor->submit (read->op, flush, false) == -1)
197 {
198 // LCOV_EXCL_START
199 this->releaseOp (read);
200 return -1;
201 // LCOV_EXCL_STOP
202 }
203
204 return static_cast<ssize_t> (index);
205 }
206
207#ifdef JOIN_HAS_IO_URING
218 ssize_t asyncReadFixed (char* data, size_t maxSize, uint16_t index, ReadHandler handler, bool flush = true,
219 bool link = false) noexcept
220 {
221 if (JOIN_UNLIKELY (!this->_socket.opened ()))
222 {
224 return -1;
225 }
226
227 AsyncRead* read = allocateRead ();
228 if (JOIN_UNLIKELY (read == nullptr))
229 {
231 return -1;
232 }
233
234 read->readHandler = std::move (handler);
235 read->op = IoOperation::makeReadFixed (this->_socket.handle (), data, maxSize, index, this, link);
236 read->op.state.store (IoOperation::State::Submitted, std::memory_order_release);
237
238 size_t slot = this->_arena.getIndex (read);
239
240 if (this->_proactor->submit (read->op, flush, false) == -1)
241 {
242 // LCOV_EXCL_START
243 this->releaseOp (read);
244 return -1;
245 // LCOV_EXCL_STOP
246 }
247
248 return static_cast<ssize_t> (slot);
249 }
250#endif
251
259 ssize_t asyncReadMulti (uint16_t group, ReadHandler handler, bool flush = true) noexcept
260 {
261 if (JOIN_UNLIKELY (!this->_socket.opened ()))
262 {
264 return -1;
265 }
266
267 AsyncRead* read = allocateRead ();
268 if (JOIN_UNLIKELY (read == nullptr))
269 {
271 return -1;
272 }
273
274 read->readHandler = std::move (handler);
275 read->op = IoOperation::makeRecvMulti (this->_socket.handle (), group, 0, this);
276 read->op.state.store (IoOperation::State::Submitted, std::memory_order_release);
277
278 size_t index = this->_arena.getIndex (read);
279
280 if (this->_proactor->submit (read->op, flush, false) == -1)
281 {
282 // LCOV_EXCL_START
283 this->releaseOp (read);
284 return -1;
285 // LCOV_EXCL_STOP
286 }
287
288 return static_cast<ssize_t> (index);
289 }
290
300 ssize_t asyncWrite (const char* data, size_t size, WriteHandler handler, bool flush = true,
301 bool link = false) noexcept
302 {
303 if (JOIN_UNLIKELY (!this->_socket.opened ()))
304 {
306 return -1;
307 }
308
309 AsyncWrite* write = allocateWrite ();
310 if (JOIN_UNLIKELY (write == nullptr))
311 {
313 return -1;
314 }
315
316 write->writeHandler = std::move (handler);
317 write->iov.iov_base = const_cast<char*> (data);
318 write->iov.iov_len = size;
319 write->msg.msg_name = nullptr;
320 write->msg.msg_namelen = 0;
321 write->msg.msg_iov = &write->iov;
322 write->msg.msg_iovlen = 1;
323 write->msg.msg_control = nullptr;
324 write->msg.msg_controllen = 0;
325 write->msg.msg_flags = 0;
326 write->op = IoOperation::makeSendmsg (this->_socket.handle (), &write->msg, MSG_NOSIGNAL, this, link);
327 write->op.state.store (IoOperation::State::Submitted, std::memory_order_release);
328
329 size_t index = this->_arena.getIndex (write);
330
331 if (this->_proactor->submit (write->op, flush, false) == -1)
332 {
333 // LCOV_EXCL_START
334 this->releaseOp (write);
335 return -1;
336 // LCOV_EXCL_STOP
337 }
338
339 return static_cast<ssize_t> (index);
340 }
341
342#ifdef JOIN_HAS_IO_URING
353 ssize_t asyncWriteFixed (const char* data, size_t size, uint16_t index, WriteHandler handler, bool flush = true,
354 bool link = false) noexcept
355 {
356 if (JOIN_UNLIKELY (!this->_socket.opened ()))
357 {
359 return -1;
360 }
361
362 AsyncWrite* write = allocateWrite ();
363 if (JOIN_UNLIKELY (write == nullptr))
364 {
366 return -1;
367 }
368
369 write->writeHandler = std::move (handler);
370 write->op = IoOperation::makeWriteFixed (this->_socket.handle (), data, size, index, this, link);
371 write->op.state.store (IoOperation::State::Submitted, std::memory_order_release);
372
373 size_t slot = this->_arena.getIndex (write);
374
375 if (this->_proactor->submit (write->op, flush, false) == -1)
376 {
377 // LCOV_EXCL_START
378 this->releaseOp (write);
379 return -1;
380 // LCOV_EXCL_STOP
381 }
382
383 return static_cast<ssize_t> (slot);
384 }
385#endif
386
391 int cancelConnect () noexcept
392 {
393 for (auto& slot : this->_ops)
394 {
395 IoOperation* op = slot.load (std::memory_order_acquire);
396
397 if ((op != nullptr) && (static_cast<IoOperation::Opcode> (op->code) == IoOperation::Opcode::Connect))
398 {
399 return this->cancelOp (op);
400 }
401 }
402
403 return 0;
404 }
405
412 int setOption (Option option, int value) noexcept
413 {
414 return this->_socket.setOption (option, value);
415 }
416
417 protected:
424 void dispatch (IoOperation& op, const std::error_code& code, size_t size) noexcept override
425 {
426 IoOperation::Opcode opcode = static_cast<IoOperation::Opcode> (op.code);
427
428 if ((opcode == IoOperation::Opcode::RecvMsg) || (opcode == IoOperation::Opcode::Recv) ||
430 {
431 completeRead (reinterpret_cast<AsyncRead*> (&op), code, size);
432 }
433 else if ((opcode == IoOperation::Opcode::SendMsg) || (opcode == IoOperation::Opcode::WriteFixed))
434 {
435 completeWrite (reinterpret_cast<AsyncWrite*> (&op), code, size);
436 }
437 else if (opcode == IoOperation::Opcode::Connect)
438 {
439 completeConnect (reinterpret_cast<AsyncWrite*> (&op), code);
440 }
441 else
442 {
444 }
445 }
446
451 void completeConnect (AsyncWrite* connect, const std::error_code& code) noexcept
452 {
453 ConnectHandler handler = std::move (connect->connectHandler);
454
455 this->releaseOp (connect);
456
457 if (code)
458 {
459 this->_socket.close ();
460 }
461 else
462 {
463 this->_socket._state = Socket::Connected;
464 }
465
466 if (JOIN_LIKELY (handler))
467 {
468 handler (code);
469 }
470 }
471
478 void completeRead (AsyncRead* read, const std::error_code& code, size_t size) noexcept
479 {
480 std::error_code result = code;
481 const char* data = nullptr;
482
483 switch (static_cast<IoOperation::Opcode> (read->op.code))
484 {
486 data = static_cast<const char*> (read->op.data.stream.buf);
487 break;
488
490 data = static_cast<const char*> (read->op.data.rw.buf);
491 break;
492
493 default:
494 data = static_cast<const char*> (read->msg.msg_iov->iov_base);
495 break;
496 }
497
498 if (this->_socket.type () == SOCK_STREAM)
499 {
500 if (JOIN_UNLIKELY (!result && (size == 0)))
501 {
503 }
504 }
505 else if (JOIN_UNLIKELY (!result && (read->msg.msg_flags & MSG_TRUNC)))
506 {
508 }
509
510 Endpoint from;
511
512 if (read->msg.msg_name != nullptr)
513 {
514 from = Endpoint (static_cast<const struct sockaddr*> (read->msg.msg_name), read->msg.msg_namelen);
515 }
516
517 if (read->op.more)
518 {
519 if (read->readFromHandler)
520 {
521 read->readFromHandler (result, data, size, from, true);
522 }
523 else if (JOIN_LIKELY (read->readHandler))
524 {
525 read->readHandler (result, data, size, true);
526 }
527
528 return;
529 }
530
531 ReadHandler handler = std::move (read->readHandler);
532 ReadFromHandler fromHandler = std::move (read->readFromHandler);
533
534 this->releaseOp (read);
535
536 if (fromHandler)
537 {
538 fromHandler (result, data, size, from, false);
539 }
540 else if (JOIN_LIKELY (handler))
541 {
542 handler (result, data, size, false);
543 }
544 }
545
551 void completeWrite (AsyncWrite* write, const std::error_code& code, size_t size) noexcept
552 {
553 WriteHandler handler = std::move (write->writeHandler);
554
555 if (JOIN_LIKELY (!write->op.multishot))
556 {
557 this->releaseOp (write);
558 }
559
560 if (JOIN_LIKELY (handler))
561 {
562 handler (code, size);
563 }
564 }
565
571 {
572 return this->template allocateOp<AsyncRead> ();
573 }
574
580 {
581 return this->template allocateOp<AsyncWrite> ();
582 }
583 };
584}
585
586#endif
uint32_t getIndex(void *p) const noexcept
get the index of a chunk in the pool.
Definition allocator.hpp:498
asynchronous raw socket class.
Definition protocol.hpp:85
AsyncRead * allocateRead() noexcept
allocate a read operation in the arena.
Definition async_raw_socket.hpp:570
BasicAsyncWrite< Protocol, Proactor > AsyncWrite
Definition async_raw_socket.hpp:57
BasicAsyncRawSocket(const BasicAsyncRawSocket &other)=delete
copy constructor.
void completeRead(AsyncRead *read, const std::error_code &code, size_t size) noexcept
invoke the read completion handler.
Definition async_raw_socket.hpp:478
typename Socket::Option Option
Definition async_raw_socket.hpp:55
int canRead() const noexcept
get the number of readable bytes.
Definition async_raw_socket.hpp:151
BasicAsyncRawSocket & operator=(const BasicAsyncRawSocket &other)=delete
copy assignment operator.
BasicAsyncRawSocket(Socket &&sock, Proactor &proactor=ProactorThread::proactor())
create the socket instance adopting an already opened socket.
Definition async_raw_socket.hpp:77
int bindToDevice(const std::string &device) noexcept
assign the specified device to the socket.
Definition async_raw_socket.hpp:142
typename AsyncWrite::Write WriteHandler
Definition async_raw_socket.hpp:61
typename Protocol::Socket Socket
Definition async_raw_socket.hpp:53
typename Protocol::Endpoint Endpoint
Definition async_raw_socket.hpp:54
ssize_t asyncWrite(const char *data, size_t size, WriteHandler handler, bool flush=true, bool link=false) noexcept
start an asynchronous write.
Definition async_raw_socket.hpp:300
void completeWrite(AsyncWrite *write, const std::error_code &code, size_t size) noexcept
invoke the write completion handler.
Definition async_raw_socket.hpp:551
ssize_t asyncReadMulti(uint16_t group, ReadHandler handler, bool flush=true) noexcept
start an asynchronous multishot read, staying armed until cancelled or failed.
Definition async_raw_socket.hpp:259
typename AsyncRead::Read ReadHandler
Definition async_raw_socket.hpp:58
typename AsyncWrite::Connect ConnectHandler
Definition async_raw_socket.hpp:60
ssize_t asyncRead(char *data, size_t maxSize, ReadHandler handler, bool flush=true, bool link=false) noexcept
start an asynchronous read.
Definition async_raw_socket.hpp:165
int bind(const Endpoint &endpoint) noexcept
assign the specified endpoint to the socket.
Definition async_raw_socket.hpp:132
~BasicAsyncRawSocket()
destroy the socket instance.
Definition async_raw_socket.hpp:122
BasicAsyncRawSocket(Proactor &proactor=ProactorThread::proactor())
create the socket instance.
Definition async_raw_socket.hpp:67
typename AsyncRead::ReadFrom ReadFromHandler
Definition async_raw_socket.hpp:59
int cancelConnect() noexcept
cancel the connect operation in flight, if any.
Definition async_raw_socket.hpp:391
BasicAsyncRead< Protocol, Proactor > AsyncRead
Definition async_raw_socket.hpp:56
BasicAsyncRawSocket(BasicAsyncRawSocket &&other) noexcept
move constructor.
Definition async_raw_socket.hpp:99
int setOption(Option option, int value) noexcept
set the given option to the given value.
Definition async_raw_socket.hpp:412
void completeConnect(AsyncWrite *connect, const std::error_code &code) noexcept
invoke the connect completion handler.
Definition async_raw_socket.hpp:451
AsyncWrite * allocateWrite() noexcept
allocate a write operation in the arena.
Definition async_raw_socket.hpp:579
void dispatch(IoOperation &op, const std::error_code &code, size_t size) noexcept override
invoke the completion handler of the given operation, then release it.
Definition async_raw_socket.hpp:424
basic asynchronous socket class.
Definition protocol.hpp:82
Socket _socket
Definition async_socket.hpp:629
void close() noexcept
Definition async_socket.hpp:171
virtual void dispatch(IoOperation &op, const std::error_code &code, size_t size) noexcept
invoke the completion handler of the given operation, then release it.
Definition async_socket.hpp:432
void releaseOp(Op *operation) noexcept
Definition async_socket.hpp:525
int cancelOp(IoOperation *op) noexcept
Definition async_socket.hpp:588
OpArena _arena
Definition async_socket.hpp:632
Op * allocateOp() noexcept
Definition async_socket.hpp:504
BasicAsyncSocket & operator=(const BasicAsyncSocket &other)=delete
copy assignment operator.
std::array< std::atomic< IoOperation * >, _opCount > _ops
Definition async_socket.hpp:635
BasicProactor * _proactor
Definition async_socket.hpp:626
void resumeAll() noexcept
Definition async_socket.hpp:546
BasicAsyncSocket(BasicProactor &proactor=ProactorThread::proactor())
Definition async_socket.hpp:76
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
Definition acceptor.hpp:32
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
Definition error.hpp:144
asynchronous read operation.
Definition async_operation.hpp:89
Function< void(const std::error_code &, const char *, size_t, bool), 16 > Read
handler invoked on completion.
Definition async_operation.hpp:93
IoOperation op
operation submitted to the proactor.
Definition async_operation.hpp:99
iovec iov
read scatter gather entry.
Definition async_operation.hpp:111
msghdr msg
read message header.
Definition async_operation.hpp:108
Read readHandler
handler invoked on completion.
Definition async_operation.hpp:102
Function< void(const std::error_code &, const char *, size_t, const Endpoint &, bool), 16 > ReadFrom
handler invoked on completion, reporting the endpoint the data are coming from.
Definition async_operation.hpp:96
asynchronous write operation.
Definition async_operation.hpp:119
Function< void(const std::error_code &), 16 > Connect
handler invoked on connection completion.
Definition async_operation.hpp:121
Function< void(const std::error_code &, size_t), 16 > Write
handler invoked on completion.
Definition async_operation.hpp:124
Write writeHandler
handler invoked on completion.
Definition async_operation.hpp:133
msghdr msg
write message header.
Definition async_operation.hpp:136
iovec iov
write scatter gather entry.
Definition async_operation.hpp:139
IoOperation op
operation submitted to the proactor.
Definition async_operation.hpp:127
Describes a single asynchronous operation submitted to the Proactor.
Definition io_operation.hpp:47
static IoOperation makeSendmsg(int fd, const msghdr *msg, int flags, CompletionHandler *handler, bool linked=false) noexcept
build a send-message operation.
Definition io_operation.cpp:263
static IoOperation makeReadFixed(int fd, void *buf, uint32_t len, uint16_t index, CompletionHandler *handler, bool linked=false) noexcept
build a fixed-buffer read operation.
Definition io_operation.cpp:189
static IoOperation makeRecvMulti(int fd, uint16_t group, int flags, CompletionHandler *handler) noexcept
build a multishot receive operation.
Definition io_operation.cpp:298
static IoOperation makeWriteFixed(int fd, const void *buf, uint32_t len, uint16_t index, CompletionHandler *handler, bool linked=false) noexcept
build a fixed-buffer write operation.
Definition io_operation.cpp:208
static IoOperation makeRecvmsg(int fd, msghdr *msg, int flags, CompletionHandler *handler, bool linked=false) noexcept
build a receive-message operation.
Definition io_operation.cpp:227
std::atomic< State > state
operation state.
Definition io_operation.hpp:392
uint8_t code
operation code.
Definition io_operation.hpp:389
Opcode
operation code.
Definition io_operation.hpp:63
#define JOIN_LIKELY(x)
Definition utils.hpp:45
#define JOIN_UNLIKELY(x)
Definition utils.hpp:46