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 <chrono>
37#include <memory>
38#include <string>
39
40// C.
41#include <linux/icmp.h>
42#include <fcntl.h>
43#include <poll.h>
44
45namespace join
46{
50 template <class Protocol>
52 {
54 template <class P, class E, size_t N>
55 friend class BasicAsyncRawSocket;
56
57 public:
58 using Ptr = std::unique_ptr<BasicSocket<Protocol>>;
59 using Endpoint = typename Protocol::Endpoint;
60 using TimePoint = std::chrono::steady_clock::time_point;
61
65 enum Mode
66 {
69 };
70
82
86 BasicSocket () noexcept
88 {
89 }
90
95 explicit BasicSocket (Mode mode) noexcept
96 : _mode (mode)
97 {
98 }
99
104 BasicSocket (const BasicSocket& other) = delete;
105
111 BasicSocket& operator= (const BasicSocket& other) = delete;
112
117 BasicSocket (BasicSocket&& other) noexcept
118 : _state (other._state)
119 , _mode (other._mode)
120 , _handle (other._handle)
121 , _protocol (other._protocol)
122 {
123 other._state = State::Closed;
124 other._mode = Mode::NonBlocking;
125 other._handle = -1;
126 other._protocol = Protocol ();
127 }
128
135 {
136 close ();
137
138 _state = other._state;
139 _mode = other._mode;
140 _handle = other._handle;
141 _protocol = other._protocol;
142
143 other._state = State::Closed;
144 other._mode = Mode::NonBlocking;
145 other._handle = -1;
146 other._protocol = Protocol ();
147
148 return *this;
149 }
150
154 virtual ~BasicSocket ()
155 {
156 if (_handle != -1)
157 {
159 }
160 }
161
167 virtual int open (const Protocol& protocol = Protocol ()) noexcept
168 {
169 if (_state != State::Closed)
170 {
171 lastError = make_error_code (Errc::InUse);
172 return -1;
173 }
174
176 {
177 _handle = ::socket (protocol.family (), protocol.type () | SOCK_NONBLOCK, protocol.protocol ());
178 }
179 else
180 {
181 _handle = ::socket (protocol.family (), protocol.type (), protocol.protocol ());
182 }
183
184 if (_handle == -1)
185 {
186 // LCOV_EXCL_START
187 lastError = std::error_code (errno, std::generic_category ());
188 close ();
189 return -1;
190 // LCOV_EXCL_STOP
191 }
192
195
196 return 0;
197 }
198
202 virtual void close () noexcept
203 {
204 if (_state != State::Closed)
205 {
208 _handle = -1;
209 }
210 }
211
217 virtual int bind (const Endpoint& endpoint) noexcept
218 {
219 if ((_state == State::Closed) && (open (endpoint.protocol ()) == -1))
220 {
221 return -1; // LCOV_EXCL_LINE
222 }
223
224 if (::bind (_handle, endpoint.addr (), endpoint.length ()) == -1)
225 {
226 lastError = std::error_code (errno, std::generic_category ());
227 return -1;
228 }
229
230 return 0;
231 }
232
237 bool waitReadyRead () const noexcept
238 {
239 return (waitUntil (true, false, TimePoint::max ()) == 0);
240 }
241
247 bool waitReadyRead (std::chrono::nanoseconds timeout) const noexcept
248 {
249 return (waitUntil (true, false, std::chrono::steady_clock::now () + timeout) == 0);
250 }
251
257 bool waitReadyRead (TimePoint deadline) const noexcept
258 {
259 return (waitUntil (true, false, deadline) == 0);
260 }
261
266 bool waitReadyWrite () const noexcept
267 {
268 return (waitUntil (false, true, TimePoint::max ()) == 0);
269 }
270
276 bool waitReadyWrite (std::chrono::nanoseconds timeout) const noexcept
277 {
278 return (waitUntil (false, true, std::chrono::steady_clock::now () + timeout) == 0);
279 }
280
286 bool waitReadyWrite (TimePoint deadline) const noexcept
287 {
288 return (waitUntil (false, true, deadline) == 0);
289 }
290
295 void setMode (Mode mode) noexcept
296 {
297 _mode = mode;
298
299 if (_state != State::Closed)
300 {
301 int flags = ::fcntl (_handle, F_GETFL, 0);
302
304 {
305 flags = flags | O_NONBLOCK;
306 }
307 else
308 {
309 flags = flags & ~O_NONBLOCK;
310 }
311
312 ::fcntl (_handle, F_SETFL, flags);
313 }
314 }
315
320 Endpoint localEndpoint () const noexcept
321 {
322 struct sockaddr_storage sa;
323 socklen_t sa_len = sizeof (struct sockaddr_storage);
324
325 if (::getsockname (_handle, reinterpret_cast<struct sockaddr*> (&sa), &sa_len) == -1)
326 {
327 return {};
328 }
329
330 return Endpoint (reinterpret_cast<struct sockaddr*> (&sa), sa_len);
331 }
332
337 bool opened () const noexcept
338 {
339 return (_state != State::Closed);
340 }
341
346 int family () const noexcept
347 {
348 return _protocol.family ();
349 }
350
355 int type () const noexcept
356 {
357 return _protocol.type ();
358 }
359
364 int protocol () const noexcept
365 {
366 return _protocol.protocol ();
367 }
368
373 Mode mode () const noexcept
374 {
375 return _mode;
376 }
377
382 int handle () const noexcept
383 {
384 return _handle;
385 }
386
393 int wait (bool wantRead, bool wantWrite) const noexcept
394 {
395 return waitUntil (wantRead, wantWrite, TimePoint::max ());
396 }
397
405 int waitFor (bool wantRead, bool wantWrite, std::chrono::nanoseconds timeout) const noexcept
406 {
407 return waitUntil (wantRead, wantWrite, std::chrono::steady_clock::now () + timeout);
408 }
409
417 int waitUntil (bool wantRead, bool wantWrite, TimePoint deadline) const noexcept
418 {
419 struct pollfd handle;
420 handle.fd = _handle;
421 handle.events = 0;
422 handle.revents = 0;
423
424 if (wantRead)
425 {
426 handle.events |= POLLIN;
427 }
428
429 if (wantWrite)
430 {
431 handle.events |= POLLOUT;
432 }
433
434 struct timespec ts = {};
435 const struct timespec* remaining = nullptr;
436
437 if (deadline != TimePoint::max ())
438 {
439 ts = toTimespec (std::max (deadline - std::chrono::steady_clock::now (), TimePoint::duration::zero ()));
440 remaining = &ts;
441 }
442
443 int nset = (handle.fd > -1) ? ::ppoll (&handle, 1, remaining, nullptr) : -1;
444 if (nset != 1)
445 {
446 if (nset == -1)
447 {
448 if (handle.fd == -1)
449 {
450 errno = EBADF;
451 }
452 lastError = std::error_code (errno, std::generic_category ());
453 }
454 else
455 {
456 lastError = make_error_code (Errc::TimedOut);
457 }
458
459 return -1;
460 }
461
462 return 0;
463 }
464
465 protected:
468
471
473 int _handle = -1;
474
476 Protocol _protocol;
477 };
478
485 template <class Protocol>
486 inline bool operator< (const BasicSocket<Protocol>& a, const BasicSocket<Protocol>& b) noexcept
487 {
488 return a.handle () < b.handle ();
489 }
490}
491
492#endif
asynchronous raw socket class.
Definition protocol.hpp:85
basic socket class.
Definition socket.hpp:52
bool opened() const noexcept
check if the socket is opened.
Definition socket.hpp:337
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:167
std::chrono::steady_clock::time_point TimePoint
Definition socket.hpp:60
Mode mode() const noexcept
get the blocking mode of the socket.
Definition socket.hpp:373
void setMode(Mode mode) noexcept
set the socket to the non-blocking or blocking mode.
Definition socket.hpp:295
State
socket states.
Definition socket.hpp:75
@ Disconnected
Definition socket.hpp:79
@ Connecting
Definition socket.hpp:76
@ Disconnecting
Definition socket.hpp:78
@ Closed
Definition socket.hpp:80
@ Connected
Definition socket.hpp:77
Protocol _protocol
protocol.
Definition socket.hpp:476
int wait(bool wantRead, bool wantWrite) const noexcept
wait for the socket handle to become ready.
Definition socket.hpp:393
Mode _mode
socket mode.
Definition socket.hpp:470
virtual void close() noexcept
close the socket.
Definition socket.hpp:202
int family() const noexcept
get socket address family.
Definition socket.hpp:346
Mode
socket modes.
Definition socket.hpp:66
@ Blocking
Definition socket.hpp:67
@ NonBlocking
Definition socket.hpp:68
std::unique_ptr< BasicSocket< Protocol > > Ptr
Definition socket.hpp:58
virtual ~BasicSocket()
destroy the socket instance.
Definition socket.hpp:154
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:405
BasicSocket(Mode mode) noexcept
create socket instance specifying the mode.
Definition socket.hpp:95
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:417
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:247
virtual int bind(const Endpoint &endpoint) noexcept
assigns the specified endpoint to the socket.
Definition socket.hpp:217
BasicSocket(BasicSocket &&other) noexcept
move constructor.
Definition socket.hpp:117
bool waitReadyRead(TimePoint deadline) const noexcept
block until new data is available for reading, giving up at the given time point.
Definition socket.hpp:257
int type() const noexcept
get the protocol communication semantic.
Definition socket.hpp:355
State _state
socket state.
Definition socket.hpp:467
typename Protocol::Endpoint Endpoint
Definition socket.hpp:59
BasicSocket() noexcept
default constructor.
Definition socket.hpp:86
Endpoint localEndpoint() const noexcept
determine the local endpoint associated with this socket.
Definition socket.hpp:320
bool waitReadyRead() const noexcept
block until new data is available for reading.
Definition socket.hpp:237
int handle() const noexcept
get socket native handle.
Definition socket.hpp:382
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:276
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:286
int protocol() const noexcept
get socket protocol.
Definition socket.hpp:364
int _handle
socket handle.
Definition socket.hpp:473
BasicSocket(const BasicSocket &other)=delete
copy constructor.
bool waitReadyWrite() const noexcept
block until at least one byte can be written.
Definition socket.hpp:266
Definition acceptor.hpp:32
struct timespec toTimespec(std::chrono::time_point< Clock, Duration > timePoint)
converts time_point to timespec.
Definition utils.hpp:462
bool operator<(const BasicDatagramSocket< Protocol > &a, const BasicDatagramSocket< Protocol > &b) noexcept
compare if socket handle is inferior.
Definition datagram_socket.hpp:394
std::error_code make_error_code(join::Errc code) noexcept
Create an std::error_code object.
Definition error.cpp:195