libcosmos
Linux C++ System Programming Library
All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
message_header.hxx
Go to the documentation of this file.
1#pragma once
2
3// C++
4#include <cstring>
5#include <optional>
6
7// Cosmos
8#include <cosmos/dso_export.h>
9#include <cosmos/error/RuntimeError.hxx>
10#include <cosmos/io/iovector.hxx>
11#include <cosmos/net/SocketAddress.hxx>
12#include <cosmos/net/types.hxx>
13
27namespace cosmos {
28
30
37 const void *msg_name;
38 socklen_t msg_namelen;
39 const struct iovec *msg_iov;
40 size_t msg_iovlen;
41 const void *msg_control;
42 size_t msg_controllen;
43 int msg_flags;
44};
45
47
55template <typename MSGHDR>
57public: // functions
58
61 clear();
62 // by default mark file descriptor received via unix domain
63 // sockets CLOEXEC.
64 setIOFlags(MessageFlags{MessageFlag::CLOEXEC});
65 }
66
68 void clear() {
69 std::memset(&m_header, 0, sizeof(m_header));
70 }
71
73
83 void setIOFlags(const MessageFlags flags) {
84 m_io_flags = flags;
85 }
86
87protected: // functions
88
90 void resetAddress() {
91 m_header.msg_name = nullptr;
92 m_header.msg_namelen = 0;
93 }
94
96 template <typename IOVEC>
97 void setIov(IOVEC &iovec) {
98 if (iovec.empty()) {
99 m_header.msg_iov = nullptr;
100 m_header.msg_iovlen = 0;
101 } else {
102 m_header.msg_iov = iovec.raw();
103 m_header.msg_iovlen = iovec.size();
104 }
105 }
106
109 return m_io_flags;
110 }
111
112protected: // data
113
115 MSGHDR m_header;
118};
119
121
142 public MessageHeaderBase<msghdr_const> {
143 friend class Socket;
144public: // types
145
147
153 template <OptLevel, typename MSG_TYPE>
154 friend class AncillaryMessage;
155 friend class SendMessageHeader;
156 protected: // functions
157
159
171 ControlMessage(const OptLevel level, int type, const size_t data_len);
172
174
178 uint8_t* data() {
179 return CMSG_DATA(m_header);
180 }
181
182 const uint8_t* data() const {
183 return CMSG_DATA(m_header);
184 }
185
187 size_t dataSpace() const {
188 return data() - reinterpret_cast<const uint8_t*>(raw());
189 }
190
192 const void* raw() const {
193 return m_buffer.data();
194 }
195
197 size_t size() const {
198 return m_buffer.size();
199 }
200
201 protected: // data
202
204 std::vector<uint8_t> m_buffer;
206 struct cmsghdr *m_header = nullptr;
207 };
208
209public: // data
210
214 std::optional<ControlMessage> control_msg;
215
216protected: // functions
217
219 void prepareSend(const SocketAddress *addr);
220
222 void postSend(size_t sent) {
223 iovec.update(sent);
224 control_msg.reset();
225 }
226
228 void setAddress(const SocketAddress &addr);
229
231 const struct msghdr* rawHeader() const {
232 return reinterpret_cast<const struct msghdr*>(&m_header);
233 }
234};
235
237
250class COSMOS_API ReceiveMessageHeader :
251 public MessageHeaderBase<msghdr> {
252 friend class Socket;
253public: // types
254
257 template <OptLevel, typename MSG_TYPE>
258 friend class AncillaryMessage;
259 protected: // functions
260
262 int type() const {
263 return m_header.cmsg_type;
264 }
265
267 auto length() const {
268 return m_header.cmsg_len;
269 }
270
271 public: // functions
272
274
278 OptLevel level() const {
279 return OptLevel{m_header.cmsg_level};
280 }
281
283 std::optional<UnixMessage> asUnixMessage() const {
284 if (level() == OptLevel::SOCKET) {
285 return UnixMessage{type()};
286 }
287
288 return std::nullopt;
289 }
290
291 std::optional<IP4Message> asIP4Message() const {
292 if (level() == OptLevel::IP) {
293 return IP4Message{type()};
294 }
295
296 return std::nullopt;
297 }
298
299 std::optional<IP6Message> asIP6Message() const {
300 if (level() == OptLevel::IPV6) {
301 return IP6Message{type()};
302 }
303
304 return std::nullopt;
305 }
306
308
314 const void* data() const {
315 return CMSG_DATA(&m_header);
316 }
317
319 size_t dataLength() const {
320 return length() - sizeof(m_header);
321 }
322
323 protected: // data
324
326 struct cmsghdr m_header;
327 };
328
331 public: // functions
332
335
337
342 m_pos{CMSG_FIRSTHDR(&header.m_header)},
343 m_header{&header} {
344 }
345
347 auto& operator++() {
348 if (m_pos) {
349 const msghdr *hdr = m_header->rawHeader();
350 const cmsghdr *chdr = m_pos;
351 m_pos = CMSG_NXTHDR(const_cast<msghdr*>(hdr), const_cast<cmsghdr*>(chdr));
352 } else {
353 cosmos_throw (RuntimeError("Attempt to increment ControlMessageIterator past the end"));
354 }
355
356 return *this;
357 }
358
359 bool operator==(const ControlMessageIterator &other) const {
360 return m_pos == other.m_pos;
361 }
362
363 bool operator!=(const ControlMessageIterator &other) const {
364 return !(*this == other);
365 }
366
369 if (!m_pos) {
370 cosmos_throw (RuntimeError("Attempt to dereference an invalid ControlMessageIterator"));
371 }
372
373 return *reinterpret_cast<const ControlMessage*>(m_pos);
374 }
375
376 protected: // data
377
378 const cmsghdr *m_pos = nullptr;
379 const ReceiveMessageHeader *m_header = nullptr;
380 };
381
382
383public: // data
384
387
388public: // functions
389
392 return MessageFlags{m_header.msg_flags};
393 }
394
396
409 void setControlBufferSize(const size_t bytes);
410
413 setControlBufferSize(0);
414 }
415
416 ControlMessageIterator begin() {
417 return ControlMessageIterator{*this};
418 }
419
420 ControlMessageIterator end() {
421 return ControlMessageIterator{};
422 }
423
424protected: // functions
425
427 void prepareReceive(SocketAddress *addr);
428
430 void postReceive(size_t received) {
431 iovec.update(received);
432 }
433
435 void setAddress(SocketAddress &addr);
436
437 struct msghdr* rawHeader() {
438 return &m_header;
439 }
440
441 const struct msghdr* rawHeader() const {
442 return &m_header;
443 }
444
445protected: // data
446
448 std::vector<uint8_t> m_control_buffer;
449};
450
452
458template <OptLevel level, typename MSG_TYPE>
460protected: // functions
461
462 SendMessageHeader::ControlMessage createMsg(MSG_TYPE type, const size_t data_len) const {
463 return SendMessageHeader::ControlMessage{level, to_integral(type), data_len};
464 }
465
466 void checkMsg(const ReceiveMessageHeader::ControlMessage &msg, MSG_TYPE type) const {
467 if (msg.level() != level || type != MSG_TYPE(msg.type())) {
468 cosmos_throw(RuntimeError("ancillary message type mismatch"));
469 }
470 }
471
472 uint8_t* data(SendMessageHeader::ControlMessage &msg) const {
473 return msg.data();
474 }
475};
476
477} // end ns
Base class for types that deal with (de)serializing ancillary socket messages.
bool update(size_t processed_bytes)
Update the vector given the number of bytes processed by a system call.
Definition iovector.cxx:11
Base class for SendMessageHeader and ReceiveMessageHeader.
MessageFlags ioFlags() const
Returns the currently set MessageFlags for send/receive.
MessageHeaderBase()
Create a MSGHDR initialized to all zeroes and with default flags applied.
MSGHDR m_header
The low level struct msghdr
MessageFlags m_io_flags
The currently configured send/receive flags.
void resetAddress()
Reset the address portion of the msghdr struct.
void setIOFlags(const MessageFlags flags)
Set the flags used for sending or receiving data.
void setIov(IOVEC &iovec)
Set the msg_iov fields of the msghdr struct based on the given iovector object.
void clear()
Clear the complete system call structure with zeroes.
Helper type for iterating over ControlMessage instances received in a ReceiveMessageHeader.
const ControlMessage & operator*()
Access the current ControlMessage the iterator points to.
auto & operator++()
Advance to the next ControlMessage, or to the end of the range.
ControlMessageIterator()
Create an invalid (end) iterator.
ControlMessageIterator(const ReceiveMessageHeader &header)
Create an iterator pointing to the first ControlMessage of header.
Wrapper for struct cmsghdr used for iterating over received control messages.
std::optional< UnixMessage > asUnixMessage() const
Return the UnixMessage ancillary message type, if applicable.
auto length() const
Returns the length of this control message including the header.
int type() const
Returns the raw control message type (which is a different type depending on level().
const void * data() const
Returns the data portion of the control message.
size_t dataLength() const
The amount of bytes found at data().
OptLevel level() const
This defines the basic option level this control message is for.
Wrapper for struct msghdr for receiving message via Socket::receiveMessage().
void clearControlBuffer()
No longer receive control messages.
std::vector< uint8_t > m_control_buffer
Optional buffer used to receive ancillary messages.
MessageFlags flags() const
Returns the MessageFlags provided by the last recvmsg() operation.
ReadIOVector iovec
Memory regions to receive data into.
void postReceive(size_t received)
Perform any cleanup or bookkeeping after a successful recvmsg() operation.
Exception type for generic runtime errors.
Wrapper for struct cmsghdr used for creating new control messages for sending.
struct cmsghdr * m_header
Pointer to the beginning of m_buffer for setting header data.
size_t dataSpace() const
Returns the amount of bytes that can be stored at data().
ControlMessage(const OptLevel level, int type, const size_t data_len)
Creates a new control message for the given level, type and size.
size_t size() const
Returns the size of the complete control message for the msg_controllen field in struct msghdr.
uint8_t * data()
Returns the data portion of the control message.
const void * raw() const
Returns the pointer to the complete control message for the msg_control field in struct msghdr.
std::vector< uint8_t > m_buffer
The raw data the control message is composed of.
Wrapper for struct msghdr for sending messages via Socket::sendMessage().
std::optional< ControlMessage > control_msg
Control message to send, if any.
void setAddress(const SocketAddress &addr)
Fill in the target address fields of the struct msghdr for the given address object.
void postSend(size_t sent)
Perform any cleanup or bookkeeping after a successful sendmsg() operation.
const struct msghdr * rawHeader() const
Return a pointer to the raw struct msghdr for passing to the sendmsg() system call.
WriteIOVector iovec
Memory regions to send.
void prepareSend(const SocketAddress *addr)
Prepare a sendmsg() operation using the given optional target address.
Base class for all types of socket addresses.
Base class for Socket types with ownership of a FileDescriptor.
Definition Socket.hxx:38
IP6Message
Ancillary message types available for IPv6 based sockets.
Definition types.hxx:280
OptLevel
Representation of socket option levels.
Definition types.hxx:90
UnixMessage
Ancillary message types available for UNIX domain sockets.
Definition types.hxx:259
IP4Message
Ancillary message types available for IPv4 based sockets.
Definition types.hxx:266
Remodelling of struct msghdr with const semantics.