join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
datagram_socket.hpp
Go to the documentation of this file.
1
25#ifndef JOIN_CORE_DATAGRAM_SOCKET_HPP
26#define JOIN_CORE_DATAGRAM_SOCKET_HPP
27
28// libjoin.
29#include <join/raw_socket.hpp>
30
31// C.
32#include <cstring>
33
34namespace join
35{
39 template <class Protocol>
40 class BasicDatagramSocket final : public BasicRawSocket<Protocol>
41 {
42 public:
43 using Ptr = std::unique_ptr<BasicDatagramSocket<Protocol>>;
47 using Endpoint = typename Protocol::Endpoint;
48
56
61 explicit BasicDatagramSocket (int ttl) noexcept
62 : BasicDatagramSocket (Mode::NonBlocking, ttl)
63 {
64 }
65
71 explicit BasicDatagramSocket (Mode mode, int ttl = 60) noexcept
72 : BasicRawSocket<Protocol> (mode)
73 , _ttl (ttl)
74 {
75 }
76
82
89
95 : BasicRawSocket<Protocol> (std::move (other))
96 , _remote (std::move (other._remote))
97 , _ttl (other._ttl)
98 {
99 other._ttl = 60;
100 }
101
108 {
109 BasicRawSocket<Protocol>::operator= (std::move (other));
110
111 _remote = std::move (other._remote);
112 _ttl = other._ttl;
113
114 other._ttl = 60;
115
116 return *this;
117 }
118
123
129 int open (const Protocol& protocol = Protocol ()) noexcept override
130 {
132 if (result == -1)
133 {
134 return -1;
135 }
136
137 int off = 0;
138
139 if ((protocol.protocol () == IPPROTO_UDP) || (protocol.protocol () == IPPROTO_TCP))
140 {
141 if ((protocol.family () == AF_INET6) &&
142 (::setsockopt (this->_handle, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof (off)) == -1))
143 {
144 // LCOV_EXCL_START
145 lastError = std::error_code (errno, std::generic_category ());
146 close ();
147 return -1;
148 // LCOV_EXCL_STOP
149 }
150 }
151
152 if ((protocol.protocol () == IPPROTO_ICMPV6) || (protocol.protocol () == IPPROTO_ICMP))
153 {
154 if ((protocol.family () == AF_INET) &&
155 (::setsockopt (this->_handle, IPPROTO_IP, IP_HDRINCL, &off, sizeof (off)) == -1))
156 {
157 // LCOV_EXCL_START
158 lastError = std::error_code (errno, std::generic_category ());
159 close ();
160 return -1;
161 // LCOV_EXCL_STOP
162 }
163
164 this->setOption (Option::MulticastTtl, _ttl);
165 this->setOption (Option::Ttl, _ttl);
166 }
167
168 return 0;
169 }
170
178 int connect (const Endpoint& endpoint) noexcept
179 {
180 if ((this->_state != State::Closed) && (this->_state != State::Disconnected))
181 {
182 lastError = make_error_code (Errc::InUse);
183 return -1;
184 }
185
186 if ((this->_state == State::Closed) && (open (endpoint.protocol ()) == -1))
187 {
188 return -1; // LCOV_EXCL_LINE
189 }
190
191 if (::connect (this->_handle, endpoint.addr (), endpoint.length ()) == -1)
192 {
193 lastError = std::error_code (errno, std::generic_category ());
194 close ();
195 return -1;
196 }
197
198 _remote = endpoint;
199 this->_state = State::Connected;
200
201 return 0;
202 }
203
208 int disconnect () noexcept
209 {
210 if (this->_state == State::Connected)
211 {
212 struct sockaddr_storage nullAddr;
213 ::memset (&nullAddr, 0, sizeof (nullAddr));
214
215 nullAddr.ss_family = AF_UNSPEC;
216
217 int result = ::connect (this->_handle, reinterpret_cast<struct sockaddr*> (&nullAddr),
218 sizeof (struct sockaddr_storage));
219 if (result == -1)
220 {
221 // LCOV_EXCL_START
222 if (errno != EAFNOSUPPORT)
223 {
224 lastError = std::error_code (errno, std::generic_category ());
225 return -1;
226 }
227 // LCOV_EXCL_STOP
228 }
229
230 this->_state = State::Disconnected;
231 _remote = {};
232 }
233
234 return 0;
235 }
236
240 void close () noexcept override
241 {
243 _remote = {};
244 }
245
253 ssize_t readFrom (char* data, size_t maxSize, Endpoint* endpoint = nullptr) noexcept
254 {
255 struct sockaddr_storage sa;
256
257 struct iovec iov;
258 iov.iov_base = data;
259 iov.iov_len = maxSize;
260
261 struct msghdr message;
262 message.msg_name = &sa;
263 message.msg_namelen = sizeof (struct sockaddr_storage);
264 message.msg_iov = &iov;
265 message.msg_iovlen = 1;
266 message.msg_control = nullptr;
267 message.msg_controllen = 0;
268
269 ssize_t size = ::recvmsg (this->_handle, &message, 0);
270 if (size == -1)
271 {
272 lastError = std::error_code (errno, std::generic_category ());
273 return -1;
274 }
275
276 if (message.msg_flags & MSG_TRUNC)
277 {
279 return -1;
280 }
281
282 if (endpoint != nullptr)
283 {
284 *endpoint = Endpoint (reinterpret_cast<struct sockaddr*> (&sa), message.msg_namelen);
285 }
286
287 return size;
288 }
289
297 ssize_t writeTo (const char* data, size_t maxSize, const Endpoint& endpoint) noexcept
298 {
299 if ((this->_state == State::Closed) && (open (endpoint.protocol ()) == -1))
300 {
301 return -1; // LCOV_EXCL_LINE
302 }
303
304 ssize_t result = ::sendto (this->_handle, data, maxSize, 0, endpoint.addr (), endpoint.length ());
305 if (result < 0)
306 {
307 lastError = std::error_code (errno, std::generic_category ());
308 return -1;
309 }
310
311 return result;
312 }
313
318 const Endpoint& remoteEndpoint () const noexcept
319 {
320 return _remote;
321 }
322
327 bool connected () const noexcept
328 {
329 return (this->_state == State::Connected);
330 }
331
336 int mtu () const noexcept
337 {
338 if (this->_state == State::Closed)
339 {
341 return -1;
342 }
343
344 int result = -1, value = -1;
345 socklen_t valueLen = sizeof (value);
346
347 if (this->family () == AF_INET6)
348 {
349 result = ::getsockopt (this->_handle, IPPROTO_IPV6, IPV6_MTU, &value, &valueLen);
350 }
351 else if (this->family () == AF_INET)
352 {
353 result = ::getsockopt (this->_handle, IPPROTO_IP, IP_MTU, &value, &valueLen);
354 }
355 else
356 {
358 return -1;
359 }
360
361 if (result == -1)
362 {
363 lastError = std::error_code (errno, std::generic_category ());
364 return -1;
365 }
366
367 return value;
368 }
369
374 int ttl () const noexcept
375 {
376 return _ttl;
377 }
378
379 protected:
382
384 int _ttl = 60;
385 };
386
393 template <class Protocol>
395 {
396 return a.handle () < b.handle ();
397 }
398}
399
400#endif
basic datagram socket class.
Definition protocol.hpp:47
typename BasicRawSocket< Protocol >::Option Option
Definition datagram_socket.hpp:45
bool connected() const noexcept
check if the socket is connected.
Definition datagram_socket.hpp:327
ssize_t writeTo(const char *data, size_t maxSize, const Endpoint &endpoint) noexcept
write data on the socket.
Definition datagram_socket.hpp:297
BasicDatagramSocket(const BasicDatagramSocket &other)=delete
Copy constructor.
const Endpoint & remoteEndpoint() const noexcept
determine the remote endpoint associated with this socket.
Definition datagram_socket.hpp:318
int mtu() const noexcept
get socket mtu.
Definition datagram_socket.hpp:336
std::unique_ptr< BasicDatagramSocket< Protocol > > Ptr
Definition datagram_socket.hpp:43
int disconnect() noexcept
remove the default remote endpoint.
Definition datagram_socket.hpp:208
Endpoint _remote
remote endpoint.
Definition datagram_socket.hpp:381
typename BasicRawSocket< Protocol >::Mode Mode
Definition datagram_socket.hpp:44
ssize_t readFrom(char *data, size_t maxSize, Endpoint *endpoint=nullptr) noexcept
read data on the socket.
Definition datagram_socket.hpp:253
int _ttl
packet time to live.
Definition datagram_socket.hpp:384
typename BasicRawSocket< Protocol >::State State
Definition datagram_socket.hpp:46
BasicDatagramSocket() noexcept
Default constructor.
Definition datagram_socket.hpp:52
~BasicDatagramSocket()=default
Destroy the instance.
typename Protocol::Endpoint Endpoint
Definition datagram_socket.hpp:47
void close() noexcept override
close the socket handle.
Definition datagram_socket.hpp:240
int connect(const Endpoint &endpoint) noexcept
assign the default remote endpoint for this socket.
Definition datagram_socket.hpp:178
BasicDatagramSocket & operator=(const BasicDatagramSocket &other)=delete
Copy assignment operator.
BasicDatagramSocket(BasicDatagramSocket &&other) noexcept
Move constructor.
Definition datagram_socket.hpp:94
BasicDatagramSocket(int ttl) noexcept
Create instance specifying the time to live.
Definition datagram_socket.hpp:61
int ttl() const noexcept
returns the Time-To-Live value.
Definition datagram_socket.hpp:374
BasicDatagramSocket(Mode mode, int ttl=60) noexcept
Create instance specifying the mode.
Definition datagram_socket.hpp:71
int open(const Protocol &protocol=Protocol()) noexcept override
open socket using the given protocol.
Definition datagram_socket.hpp:129
basic raw socket class.
Definition raw_socket.hpp:42
typename BasicSocket< Protocol >::Mode Mode
Definition raw_socket.hpp:45
typename BasicSocket< Protocol >::State State
Definition raw_socket.hpp:46
Option
socket options.
Definition raw_socket.hpp:53
BasicRawSocket & operator=(const BasicRawSocket &other)=delete
copy assignment operator.
virtual int setOption(Option option, int value) noexcept
set the given option to the given value.
Definition raw_socket.hpp:277
BasicRawSocket() noexcept
default constructor.
Definition raw_socket.hpp:76
virtual int open(const Protocol &protocol=Protocol()) noexcept
open socket using the given protocol.
Definition socket.hpp:167
Mode mode() const noexcept
get the blocking mode of the socket.
Definition socket.hpp:373
virtual void close() noexcept
close the socket.
Definition socket.hpp:202
int family() const noexcept
get socket address family.
Definition socket.hpp:346
@ NonBlocking
Definition socket.hpp:68
State _state
socket state.
Definition socket.hpp:467
int protocol() const noexcept
get socket protocol.
Definition socket.hpp:364
int _handle
socket handle.
Definition socket.hpp:473
Definition acceptor.hpp:32
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