join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
socket.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_CORE_SOCKET_HPP
26#define JOIN_CORE_SOCKET_HPP
27
28// libjoin.
29#include <join/protocol.hpp>
30#include <join/endpoint.hpp>
31#include <join/utils.hpp>
32#include <join/error.hpp>
33
34// C++.
35#include <algorithm>
36#include <compare>
37#include <chrono>
38#include <memory>
39#include <string>
40
41// C.
42#include <linux/icmp.h>
43#include <fcntl.h>
44#include <poll.h>
45
46namespace join
47{
51 template <class Protocol>
53 {
55 template <class P, class E, size_t N>
56 friend class BasicAsyncRawSocket;
57
58 public:
59 using Ptr = std::unique_ptr<BasicSocket<Protocol>>;
60 using Endpoint = typename Protocol::Endpoint;
61 using TimePoint = std::chrono::steady_clock::time_point;
62
66 enum Mode
67 {
70 };
71
83
87 BasicSocket () noexcept
89 {
90 }
91
96 explicit BasicSocket (Mode mode) noexcept
97 : _mode (mode)
98 {
99 }
100
105 BasicSocket (const BasicSocket& other) = delete;
106
112 BasicSocket& operator= (const BasicSocket& other) = delete;
113
118 BasicSocket (BasicSocket&& other) noexcept
119 : _state (other._state)
120 , _mode (other._mode)
121 , _handle (other._handle)
122 , _protocol (other._protocol)
123 {
124 other._state = State::Closed;
125 other._mode = Mode::NonBlocking;
126 other._handle = -1;
127 other._protocol = Protocol ();
128 }
129
136 {
137 close ();
138
139 _state = other._state;
140 _mode = other._mode;
141 _handle = other._handle;
142 _protocol = other._protocol;
143
144 other._state = State::Closed;
145 other._mode = Mode::NonBlocking;
146 other._handle = -1;
147 other._protocol = Protocol ();
148
149 return *this;
150 }
151
155 virtual ~BasicSocket ()
156 {
157 if (_handle != -1)
158 {
160 }
161 }
162
168 virtual int open (const Protocol& protocol = Protocol ()) noexcept
169 {
170 if (_state != State::Closed)
171 {
172 lastError = make_error_code (Errc::InUse);
173 return -1;
174 }
175
177 {
178 _handle = ::socket (protocol.family (), protocol.type () | SOCK_NONBLOCK, protocol.protocol ());
179 }
180 else
181 {
182 _handle = ::socket (protocol.family (), protocol.type (), protocol.protocol ());
183 }
184
185 if (_handle == -1)
186 {
187 // LCOV_EXCL_START
188 lastError = std::error_code (errno, std::generic_category ());
189 close ();
190 return -1;
191 // LCOV_EXCL_STOP
192 }
193
196
197 return 0;
198 }
199
203 virtual void close () noexcept
204 {
205 if (_state != State::Closed)
206 {
209 _handle = -1;
210 }
211 }
212
218 virtual int bind (const Endpoint& endpoint) noexcept
219 {
220 if ((_state == State::Closed) && (open (endpoint.protocol ()) == -1))
221 {
222 return -1; // LCOV_EXCL_LINE
223 }
224
225 if (::bind (_handle, endpoint.addr (), endpoint.length ()) == -1)
226 {
227 lastError = std::error_code (errno, std::generic_category ());
228 return -1;
229 }
230
231 return 0;
232 }
233
238 bool waitReadyRead () const noexcept
239 {
240 return (waitUntil (true, false, TimePoint::max ()) == 0);
241 }
242
248 bool waitReadyRead (std::chrono::nanoseconds timeout) const noexcept
249 {
250 return (waitUntil (true, false, std::chrono::steady_clock::now () + timeout) == 0);
251 }
252
258 bool waitReadyRead (TimePoint deadline) const noexcept
259 {
260 return (waitUntil (true, false, deadline) == 0);
261 }
262
267 bool waitReadyWrite () const noexcept
268 {
269 return (waitUntil (false, true, TimePoint::max ()) == 0);
270 }
271
277 bool waitReadyWrite (std::chrono::nanoseconds timeout) const noexcept
278 {
279 return (waitUntil (false, true, std::chrono::steady_clock::now () + timeout) == 0);
280 }
281
287 bool waitReadyWrite (TimePoint deadline) const noexcept
288 {
289 return (waitUntil (false, true, deadline) == 0);
290 }
291
296 void setMode (Mode mode) noexcept
297 {
298 _mode = mode;
299
300 if (_state != State::Closed)
301 {
302 int flags = ::fcntl (_handle, F_GETFL, 0);
303
305 {
306 flags = flags | O_NONBLOCK;
307 }
308 else
309 {
310 flags = flags & ~O_NONBLOCK;
311 }
312
313 ::fcntl (_handle, F_SETFL, flags);
314 }
315 }
316
321 Endpoint localEndpoint () const noexcept
322 {
323 struct sockaddr_storage sa;
324 socklen_t sa_len = sizeof (struct sockaddr_storage);
325
326 if (::getsockname (_handle, reinterpret_cast<struct sockaddr*> (&sa), &sa_len) == -1)
327 {
328 return {};
329 }
330
331 return Endpoint (reinterpret_cast<struct sockaddr*> (&sa), sa_len);
332 }
333
338 bool opened () const noexcept
339 {
340 return (_state != State::Closed);
341 }
342
347 int family () const noexcept
348 {
349 return _protocol.family ();
350 }
351
356 int type () const noexcept
357 {
358 return _protocol.type ();
359 }
360
365 int protocol () const noexcept
366 {
367 return _protocol.protocol ();
368 }
369
374 Mode mode () const noexcept
375 {
376 return _mode;
377 }
378
383 int handle () const noexcept
384 {
385 return _handle;
386 }
387
394 int wait (bool wantRead, bool wantWrite) const noexcept
395 {
396 return waitUntil (wantRead, wantWrite, TimePoint::max ());
397 }
398
406 int waitFor (bool wantRead, bool wantWrite, std::chrono::nanoseconds timeout) const noexcept
407 {
408 return waitUntil (wantRead, wantWrite, std::chrono::steady_clock::now () + timeout);
409 }
410
418 int waitUntil (bool wantRead, bool wantWrite, TimePoint deadline) const noexcept
419 {
420 struct pollfd handle;
421 handle.fd = _handle;
422 handle.events = 0;
423 handle.revents = 0;
424
425 if (wantRead)
426 {
427 handle.events |= POLLIN;
428 }
429
430 if (wantWrite)
431 {
432 handle.events |= POLLOUT;
433 }
434
435 struct timespec ts = {};
436 const struct timespec* remaining = nullptr;
437
438 if (deadline != TimePoint::max ())
439 {
440 ts = toTimespec (std::max (deadline - std::chrono::steady_clock::now (), TimePoint::duration::zero ()));
441 remaining = &ts;
442 }
443
444 int nset = (handle.fd > -1) ? ::ppoll (&handle, 1, remaining, nullptr) : -1;
445 if (nset != 1)
446 {
447 if (nset == -1)
448 {
449 if (handle.fd == -1)
450 {
451 errno = EBADF;
452 }
453 lastError = std::error_code (errno, std::generic_category ());
454 }
455 else
456 {
457 lastError = make_error_code (Errc::TimedOut);
458 }
459
460 return -1;
461 }
462
463 return 0;
464 }
465
466 protected:
469
472
474 int _handle = -1;
475
477 Protocol _protocol;
478 };
479
486 template <class Protocol>
487 inline bool operator== (const BasicSocket<Protocol>& a, const BasicSocket<Protocol>& b) noexcept
488 {
489 return a.handle () == b.handle ();
490 }
491
498 template <class Protocol>
499 inline std::strong_ordering operator<=> (const BasicSocket<Protocol>& a, const BasicSocket<Protocol>& b) noexcept
500 {
501 return a.handle () <=> b.handle ();
502 }
503}
504
505#endif
asynchronous raw socket class.
Definition protocol.hpp:88
basic socket class.
Definition socket.hpp:53
bool opened() const noexcept
check if the socket is opened.
Definition socket.hpp:338
BasicSocket & operator=(const BasicSocket &other)=delete
copy assignment operator.
virtual int open(const Protocol &protocol=Protocol()) noexcept
open socket using the given protocol.
Definition socket.hpp:168
std::chrono::steady_clock::time_point TimePoint
Definition socket.hpp:61
Mode mode() const noexcept
get the blocking mode of the socket.
Definition socket.hpp:374
void setMode(Mode mode) noexcept
set the socket to the non-blocking or blocking mode.
Definition socket.hpp:296
State
socket states.
Definition socket.hpp:76
@ Disconnected
Definition socket.hpp:80
@ Connecting
Definition socket.hpp:77
@ Disconnecting
Definition socket.hpp:79
@ Closed
Definition socket.hpp:81
@ Connected
Definition socket.hpp:78
Protocol _protocol
protocol.
Definition socket.hpp:477
int wait(bool wantRead, bool wantWrite) const noexcept
wait for the socket handle to become ready.
Definition socket.hpp:394
Mode _mode
socket mode.
Definition socket.hpp:471
virtual void close() noexcept
close the socket.
Definition socket.hpp:203
int family() const noexcept
get socket address family.
Definition socket.hpp:347
Mode
socket modes.
Definition socket.hpp:67
@ Blocking
Definition socket.hpp:68
@ NonBlocking
Definition socket.hpp:69
std::unique_ptr< BasicSocket< Protocol > > Ptr
Definition socket.hpp:59
virtual ~BasicSocket()
destroy the socket instance.
Definition socket.hpp:155
int waitFor(bool wantRead, bool wantWrite, std::chrono::nanoseconds timeout) const noexcept
wait for the socket handle to become ready, giving up after the given duration.
Definition socket.hpp:406
BasicSocket(Mode mode) noexcept
create socket instance specifying the mode.
Definition socket.hpp:96
int waitUntil(bool wantRead, bool wantWrite, TimePoint deadline) const noexcept
wait for the socket handle to become ready, giving up at the given time point.
Definition socket.hpp:418
bool waitReadyRead(std::chrono::nanoseconds timeout) const noexcept
block until new data is available for reading, giving up after the given duration.
Definition socket.hpp:248
virtual int bind(const Endpoint &endpoint) noexcept
assigns the specified endpoint to the socket.
Definition socket.hpp:218
BasicSocket(BasicSocket &&other) noexcept
move constructor.
Definition socket.hpp:118
bool waitReadyRead(TimePoint deadline) const noexcept
block until new data is available for reading, giving up at the given time point.
Definition socket.hpp:258
int type() const noexcept
get the protocol communication semantic.
Definition socket.hpp:356
State _state
socket state.
Definition socket.hpp:468
typename Protocol::Endpoint Endpoint
Definition socket.hpp:60
BasicSocket() noexcept
default constructor.
Definition socket.hpp:87
Endpoint localEndpoint() const noexcept
determine the local endpoint associated with this socket.
Definition socket.hpp:321
bool waitReadyRead() const noexcept
block until new data is available for reading.
Definition socket.hpp:238
int handle() const noexcept
get socket native handle.
Definition socket.hpp:383
bool waitReadyWrite(std::chrono::nanoseconds timeout) const noexcept
block until at least one byte can be written, giving up after the given duration.
Definition socket.hpp:277
bool waitReadyWrite(TimePoint deadline) const noexcept
block until at least one byte can be written, giving up at the given time point.
Definition socket.hpp:287
int protocol() const noexcept
get socket protocol.
Definition socket.hpp:365
int _handle
socket handle.
Definition socket.hpp:474
BasicSocket(const BasicSocket &other)=delete
copy constructor.
bool waitReadyWrite() const noexcept
block until at least one byte can be written.
Definition socket.hpp:267
Definition acceptor.hpp:32
bool operator==(const BasicLinkLayerEndpoint< Protocol > &a, const BasicLinkLayerEndpoint< Protocol > &b) noexcept
compare if endpoints are equal.
Definition endpoint.hpp:196
struct timespec toTimespec(std::chrono::time_point< Clock, Duration > timePoint)
converts time_point to timespec.
Definition utils.hpp:431
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195
std::strong_ordering operator<=>(const BasicLinkLayerEndpoint< Protocol > &a, const BasicLinkLayerEndpoint< Protocol > &b) noexcept
three-way compare endpoints.
Definition endpoint.hpp:208