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 ProactorType, size_t OpCount>
50 class BasicAsyncRawSocket : public BasicAsyncSocket<Protocol, ProactorType, 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
67 explicit BasicAsyncRawSocket (ProactorType& proactor = ProactorThread::proactor ())
68 : BasicAsyncSocket<Protocol, ProactorType, OpCount> (proactor)
69 {
70 }
71
77 explicit BasicAsyncRawSocket (Socket&& sock, ProactorType& proactor = ProactorThread::proactor ())
78 : BasicAsyncSocket<Protocol, ProactorType, 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 (ReadHandler handler, char* data, size_t maxSize, 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->_allocator.getIndex (read);
195
196 if (this->_proactor->submit (read->op, flush, false) == -1)
197 {
198 // LCOV_EXCL_START
199 this->releaseOperation (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 (ReadHandler handler, char* data, size_t maxSize, uint16_t index, 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->_allocator.getIndex (read);
239
240 if (this->_proactor->submit (read->op, flush, false) == -1)
241 {
242 // LCOV_EXCL_START
243 this->releaseOperation (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 (ReadHandler handler, uint16_t group, 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->_allocator.getIndex (read);
279
280 if (this->_proactor->submit (read->op, flush, false) == -1)
281 {
282 // LCOV_EXCL_START
283 this->releaseOperation (read);
284 return -1;
285 // LCOV_EXCL_STOP
286 }
287
288 return static_cast<ssize_t> (index);
289 }
290
300 ssize_t asyncWrite (WriteHandler handler, const char* data, size_t size, 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->_allocator.getIndex (write);
330
331 if (this->_proactor->submit (write->op, flush, false) == -1)
332 {
333 // LCOV_EXCL_START
334 this->releaseOperation (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 (WriteHandler handler, const char* data, size_t size, uint16_t index, 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->_allocator.getIndex (write);
374
375 if (this->_proactor->submit (write->op, flush, false) == -1)
376 {
377 // LCOV_EXCL_START
378 this->releaseOperation (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->cancelOperation (*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 if (code)
456 {
457 this->_socket.close ();
458 }
459 else
460 {
461 this->_socket._state = Socket::Connected;
462 }
463
464 this->releaseOperation (connect);
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 | MSG_CTRUNC))))
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 const char* control = nullptr;
518 size_t controlSize = 0;
519
520 if ((read->msg.msg_control != nullptr) && (read->msg.msg_controllen > 0))
521 {
522 control = static_cast<const char*> (read->msg.msg_control);
523 controlSize = read->msg.msg_controllen;
524 }
525
526 if (read->op.more)
527 {
528 if (read->readFromHandler)
529 {
530 read->readFromHandler (result, data, size, from, control, controlSize, true);
531 }
532 else if (JOIN_LIKELY (read->readHandler))
533 {
534 read->readHandler (result, data, size, true);
535 }
536
537 return;
538 }
539
540 ReadHandler handler = std::move (read->readHandler);
541 ReadFromHandler fromHandler = std::move (read->readFromHandler);
542
543 this->releaseOperation (read);
544
545 if (fromHandler)
546 {
547 fromHandler (result, data, size, from, control, controlSize, false);
548 }
549 else if (JOIN_LIKELY (handler))
550 {
551 handler (result, data, size, false);
552 }
553 }
554
560 void completeWrite (AsyncWrite* write, const std::error_code& code, size_t size) noexcept
561 {
562 WriteHandler handler = std::move (write->writeHandler);
563
564 if (JOIN_LIKELY (!write->op.multishot))
565 {
566 this->releaseOperation (write);
567 }
568
569 if (JOIN_LIKELY (handler))
570 {
571 handler (code, size);
572 }
573 }
574
580 {
581 return this->template allocateOperation<AsyncRead> ();
582 }
583
589 {
590 return this->template allocateOperation<AsyncWrite> ();
591 }
592 };
593}
594
595#endif
asynchronous raw socket class.
Definition protocol.hpp:88
BasicAsyncRawSocket(BasicAsyncRawSocket &&other) noexcept
move constructor.
Definition async_raw_socket.hpp:99
void completeWrite(AsyncWrite *write, const std::error_code &code, size_t size) noexcept
invoke the write completion handler.
Definition async_raw_socket.hpp:560
int canRead() const noexcept
get the number of readable bytes.
Definition async_raw_socket.hpp:151
typename Socket::Option Option
Definition async_raw_socket.hpp:55
ssize_t asyncRead(ReadHandler handler, char *data, size_t maxSize, bool flush=true, bool link=false) noexcept
start an asynchronous read.
Definition async_raw_socket.hpp:165
BasicAsyncRead< Protocol, ProactorType > AsyncRead
Definition async_raw_socket.hpp:56
BasicAsyncWrite< Protocol, ProactorType > AsyncWrite
Definition async_raw_socket.hpp:57
typename AsyncWrite::Write WriteHandler
Definition async_raw_socket.hpp:61
int cancelConnect() noexcept
cancel the connect operation in flight, if any.
Definition async_raw_socket.hpp:391
void completeConnect(AsyncWrite *connect, const std::error_code &code) noexcept
invoke the connect completion handler.
Definition async_raw_socket.hpp:451
int setOption(Option option, int value) noexcept
set the given option to the given value.
Definition async_raw_socket.hpp:412
AsyncWrite * allocateWrite() noexcept
allocate a write operation in the allocator.
Definition async_raw_socket.hpp:588
BasicAsyncRawSocket(Socket &&sock, ProactorType &proactor=ProactorThread::proactor())
create the socket instance adopting an already opened socket.
Definition async_raw_socket.hpp:77
BasicAsyncRawSocket(ProactorType &proactor=ProactorThread::proactor())
create the socket instance.
Definition async_raw_socket.hpp:67
~BasicAsyncRawSocket()
destroy the socket instance.
Definition async_raw_socket.hpp:122
int bindToDevice(const std::string &device) noexcept
assign the specified device to the socket.
Definition async_raw_socket.hpp:142
ssize_t asyncWrite(WriteHandler handler, const char *data, size_t size, bool flush=true, bool link=false) noexcept
start an asynchronous write.
Definition async_raw_socket.hpp:300
ssize_t asyncReadMulti(ReadHandler handler, uint16_t group, bool flush=true) noexcept
start an asynchronous multishot read, staying armed until cancelled or failed.
Definition async_raw_socket.hpp:259
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 AsyncRead::Read ReadHandler
Definition async_raw_socket.hpp:58
BasicAsyncRawSocket & operator=(const BasicAsyncRawSocket &other)=delete
copy assignment operator.
AsyncRead * allocateRead() noexcept
allocate a read operation in the allocator.
Definition async_raw_socket.hpp:579
typename Protocol::Endpoint Endpoint
Definition async_raw_socket.hpp:54
BasicAsyncRawSocket(const BasicAsyncRawSocket &other)=delete
copy constructor.
int bind(const Endpoint &endpoint) noexcept
assign the specified endpoint to the socket.
Definition async_raw_socket.hpp:132
typename Protocol::Socket Socket
Definition async_raw_socket.hpp:53
typename AsyncRead::ReadFrom ReadFromHandler
Definition async_raw_socket.hpp:59
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
typename AsyncWrite::Connect ConnectHandler
Definition async_raw_socket.hpp:60
basic asynchronous socket class.
Definition protocol.hpp:85
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:446
Socket _socket
Definition async_socket.hpp:657
void close() noexcept
Definition async_socket.hpp:171
BasicAsyncSocket(BasicProactor &proactor=ProactorThread::proactor())
Definition async_socket.hpp:76
std::array< std::atomic< IoOperation * >, _opCount > _ops
Definition async_socket.hpp:663
void releaseOperation(Op *operation) noexcept
Definition async_socket.hpp:539
void resumeAll() noexcept
Definition async_socket.hpp:566
int cancelOperation(IoOperation &op) noexcept
Definition async_socket.hpp:616
BasicAsyncSocket & operator=(const BasicAsyncSocket &other)=delete
copy assignment operator.
Op * allocateOperation() noexcept
Definition async_socket.hpp:518
BasicProactor * _proactor
Definition async_socket.hpp:654
OpAllocator _allocator
Definition async_socket.hpp:660
static BasicProactor & proactor()
get the Proactor instance owned by the singleton ProactorThread.
Definition proactor.hpp:1053
int submit(IoOperation &op, bool flush=false, bool sync=false) noexcept
submit an asynchronous operation to the proactor.
Definition proactor.hpp:741
uint32_t getIndex(void *p) const noexcept
get the index of a chunk in the pool.
Definition slab_allocator.hpp:455
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
Read readHandler
handler invoked on completion.
Definition async_operation.hpp:104
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:101
msghdr msg
read message header.
Definition async_operation.hpp:110
Function< void(const std::error_code &, const char *, size_t, const Endpoint &, const char *, size_t, bool), 16 > ReadFrom
handler invoked on completion, reporting the endpoint the data are coming from and the control messag...
Definition async_operation.hpp:96
iovec iov
read scatter gather entry.
Definition async_operation.hpp:113
asynchronous write operation.
Definition async_operation.hpp:121
msghdr msg
write message header.
Definition async_operation.hpp:138
Function< void(const std::error_code &, size_t), 16 > Write
handler invoked on completion.
Definition async_operation.hpp:126
Write writeHandler
handler invoked on completion.
Definition async_operation.hpp:135
iovec iov
write scatter gather entry.
Definition async_operation.hpp:141
Function< void(const std::error_code &), 16 > Connect
handler invoked on connection completion.
Definition async_operation.hpp:123
IoOperation op
operation submitted to the proactor.
Definition async_operation.hpp:129
Describes a single asynchronous operation submitted to the Proactor.
Definition io_operation.hpp:48
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:271
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:197
static IoOperation makeRecvMulti(int fd, uint16_t group, int flags, CompletionHandler *handler) noexcept
build a multishot receive operation.
Definition io_operation.cpp:306
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:216
static IoOperation makeRecvmsg(int fd, msghdr *msg, int flags, CompletionHandler *handler, bool linked=false) noexcept
build a receive-message operation.
Definition io_operation.cpp:235
std::atomic< State > state
operation state.
Definition io_operation.hpp:404
uint8_t code
operation code.
Definition io_operation.hpp:401
Opcode
operation code.
Definition io_operation.hpp:64
#define JOIN_LIKELY(x)
Definition utils.hpp:50
#define JOIN_UNLIKELY(x)
Definition utils.hpp:51