randolf.ca  1.00
Randolf Richardson's C++ classes
Loading...
Searching...
No Matches
rsocket_group
1#pragma once
2
3//#include <randolf/rex>
4//#include <randolf/rsocket>
5#include <randolf/rsocket_group_rc>
6#include <randolf/rtools>
7
8namespace randolf {
9
10 /*======================================================================*//**
11 @brief
12 An rsocket_group provides a means to associate multiple @ref rsocket objects
13 so that the same operation can be performed on all of them at once.
14
15 The @ref rsocket::accept() and @ref rsocket::accept4() methods can also be
16 configured to automatically assign group membership to new connections, which
17 can be particularly useful for certain types of multi-user systems.
18
19 @par Threads
20 This class is threadsafe.
21 @author Randolf Richardson
22 @version 1.00
23 @par History
24 - 2022-Dec-29 v1.00 Initial version
25 - 2025-Feb-03 v1.00 Increased use of references and pointers
26 - 2025-Feb-09 v1.00 In keeping with changes in rsocket, changed most
27 methods that return data wrapped in @c std::shared_ptr
28 to return data wrapped in @c std::unique_ptr instead
29 because this has a lot less overhead, and converting
30 from unique_ptr to shared_ptr is trivial, but the other
31 way around is not directly supported
32 - 2025-Feb-17 v1.00 Updated @ref net_io and related methods to include
33 support for the @c bytes_sx and @c crypt_sx statistics
34 *///=========================================================================
35 class rsocket_group {
36
37 private:
38 // --------------------------------------------------------------------------
39 // Comparator for use with std::set<rsocket> initialization. It simply
40 // compares the physical address of the instantiated rsocket() object since
41 // this is immediately available for the fastest possible comparison.
42 // --------------------------------------------------------------------------
43 template<typename R> struct __rsocket_cmp {
44 bool operator() (const std::weak_ptr<rsocket> r1, const std::weak_ptr<rsocket> r2) const {
45 auto _r1 = r1.lock(); if (!_r1) return false; // Expired pointer; we're done
46 auto _r2 = r2.lock(); if (!_r1) return true; // Not expired-after-expired pointer
47 return (uintptr_t)_r1.get() < (uintptr_t)_r2.get(); // Compare pointers as uint values
48 } // -x- bool operator() -x-
49 }; // -x- struct __rsocket_cmp -x-
50
51 // --------------------------------------------------------------------------
52 // Internal variables.
53 // --------------------------------------------------------------------------
54 std::mutex __mutex; // Used to ensure thread safety
55 std::set<std::weak_ptr<rsocket>, __rsocket_cmp<rsocket>> __r; // Set of rsocket objects (with our comparator)
56
57 // --------------------------------------------------------------------------
58 // Keep track of test for whether this host stores integers using big endian.
59 // --------------------------------------------------------------------------
60 inline static const bool __endian_is_msb = htons(42) == 42; // TRUE==MSB / FALSE==LSB
61
62 // --------------------------------------------------------------------------
63 // General variables. Atomic variables are used for variables as needed to
64 // support operations in a thread-safe manner.
65 // --------------------------------------------------------------------------
66 std::string __name;
67
68 public:
69 /*======================================================================*//**
70 @brief
71 Instantiate an rsocket group with no @ref rsocket objects.
72
73 @see insert()
74 *///=========================================================================
75 rsocket_group() noexcept {} // -x- constructor rsocket_group -x-
76
77 /*======================================================================*//**
78 @brief
79 Instantiate an rsocket group with any number of @ref rsocket objects.
80
81 @see insert()
82 *///=========================================================================
83 template<class R, class... Rs> rsocket_group(
84 /// Pointer to instantiated rsocket object
85 R r,
86 /// Variadic arguments (any quantity of instantiated rsocket objects)
87 Rs... rs) noexcept {
88 __insert(r);
89 __insert(rs...);
90 } // -x- constructor rsocket_group -x-
91
92 private:
93 /*======================================================================*//**
94 @brief
95 Internal method that is used by the @ref insert(rsocket*) method.
96
97 @warning
98 This method is not threadsafe.
99 *///=========================================================================
100 rsocket_group& __insert(
101 /// Pointer to instantiated rsocket object
102 rsocket* r) noexcept {
103 if (r == nullptr) return *this;
104 __r.insert(std::make_shared<rsocket>(r)); // Effectively: std::make_weak()
105 return *this;
106 } // -x- rsocket_group& __insert -x-
107
108 /*======================================================================*//**
109 @brief
110 Internal method that is used by the @ref insert(rsocket*, ...) method.
111
112 @warning
113 This method is not threadsafe.
114 *///=========================================================================
115 template<class R, class... Rs> void __insert(
116 /// Pointer to instantiated rsocket object
117 R r,
118 /// Variadic arguments (any quantity of instantiated rsocket objects)
119 Rs... rs) noexcept {
120 __insert(r);
121 __insert(rs...);
122 } // -x- void __insert -x-
123
124 public:
125 /*======================================================================*//**
126 @brief
127 Close all rsockets that are in this rsocket_group.
128 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
129 containing successful operations that also record the number of
130 bytes that were transmitted, and the second one containing failed
131 operations that also record the exception that was thrown (see the
132 @ref rsocket_group_rc structure for details)
133 @see rsocket::close()
134 *///=========================================================================
135 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& close() {
136
137 // --------------------------------------------------------------------------
138 // Internal variables.
139 // --------------------------------------------------------------------------
140 std::vector<rsocket_group_rc>* v1 = new std::vector<rsocket_group_rc>();
141 std::vector<rsocket_group_rc>* v2 = new std::vector<rsocket_group_rc>();
142 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>* pair = new std::pair(*v1, *v2);
143
144 // --------------------------------------------------------------------------
145 // Loop through all rsocket objects in the underlying std::set.
146 //
147 // We don't need a mutex lock here because the close() method is threadsafe.
148 // --------------------------------------------------------------------------
149 for (std::weak_ptr<rsocket> wp : __r) {
150 if (auto r = wp.lock()) { // Weak pointer is still valid, so acquire a std::unique_ptr while we access r
151 try {
152 r->close();
153 v1->push_back({r.get(), 0, nullptr});
154 } catch (std::exception* e) {
155 v2->push_back({r.get(), 0, e});
156 }
157 } // -x- if r.lock() -x-
158 } // -x- foreach __r -x-
159
160 return *pair;
161 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& close -x-
162
163 /*======================================================================*//**
164 @brief
165 Remove an rsocket object from the underlying std::set.
166
167 @par Threads
168 This method is threadsafe.
169 *///=========================================================================
170 rsocket_group& erase(
171 /// Pointer to instantiated rsocket object
172 rsocket* r) {
173 {
174 const std::lock_guard<std::mutex> lock(__mutex);
175 __r.erase(std::make_shared<rsocket>(r)); // Effectively: std::make_weak()
176 }
177 return *this;
178 } // -x- rsocket_group& erase -x-
179
180 /*======================================================================*//**
181 @brief
182 Add one rsocket object to the underlying std::set.
183
184 @par Threads
185 This method is threadsafe.
186 *///=========================================================================
187 rsocket_group& insert(
188 /// Pointer to instantiated rsocket object
189 rsocket* r) {
190 const std::lock_guard<std::mutex> lock(__mutex);
191 __insert(r);
192 return *this;
193 } // -x- rsocket_group& insert -x-
194
195 /*======================================================================*//**
196 @brief
197 Add one or more rsocket objects to the underlying std::set.
198
199 @par Threads
200 This method is threadsafe.
201 *///=========================================================================
202 template<class R, class... Rs> rsocket_group& insert(
203 /// Pointer to instantiated rsocket object
204 R r,
205 /// Variadic arguments (any quantity of instantiated rsocket objects)
206 Rs... rs) {
207 const std::lock_guard<std::mutex> lock(__mutex);
208 __insert(r);
209 __insert(rs...);
210 return *this;
211 } // -x- rsocket_group& insert -x-
212
213 /*======================================================================*//**
214 @brief
215 Specify a name for this rsocket_group.
216
217 This is an arbitrary name that is entirely optional, and should be regarded
218 as similar to the naming of threads.
219
220 @par Threads
221 This method is threadsafe.
222 *///=========================================================================
223 rsocket_group& name(
224 /// Name to assign to this rsocket_group
225 const std::string& name) noexcept {
226 const std::lock_guard<std::mutex> lock(__mutex);
227 __name = name;
228 return *this;
229 } // -x- rsocket_group& name -x-
230
231 /*======================================================================*//**
232 @brief
233 Find out what this rsocket_group's name is.
234
235 @par Threads
236 This method is threadsafe.
237 @returns The name of this rsocket (or an empty std::string if this rsocket
238 doesn't have a name)
239 *///=========================================================================
240 std::string name() noexcept {
241 const std::lock_guard<std::mutex> lock(__mutex);
242 return __name;
243 } // -x- std::string name -x-
244
245 /*======================================================================*//**
246 @brief
247 Get the combined total of socket I/O statistics from all rsocket objects in
248 this group.
249
250 The number of bytes transmitted and received is tracked internally, so that
251 the information can be used later in logging. These statistics are available
252 at all times, but for logging purposes it makes the most sense to copy this
253 information after the rsocket is closed, at which time the final statistics
254 will continue to be available until the rsocket's destructor takes over.
255
256 @par Threads
257 This method is threadsafe.
258 @returns rsocket_io wrapped in a std::unique_ptr object to help ease memory
259 management efforts
260 @see rsocket::net_io()
261 *///=========================================================================
262 std::unique_ptr<rsocket_io> net_io() noexcept {
263 std::unique_ptr stats = std::make_unique<rsocket_io>();
264
265 // --------------------------------------------------------------------------
266 // Loop through all rsocket objects in the underlying std::set.
267 //
268 // We don't need a mutex lock here because the stastical rx/tx counters in
269 // every rsocket class are atomic variables.
270 // --------------------------------------------------------------------------
271 for (std::weak_ptr<rsocket> wp : __r) {
272 if (auto r = wp.lock()) { // Weak pointer is still valid, so acquire a std::unique_ptr while we access r
273 stats->bytes_rx += r->__bytes_rx;
274 stats->bytes_tx += r->__bytes_tx;
275 stats->bytes_sx += r->__tls ? 0 : (r->__buffer != nullptr ? r->__buffer->get_utilized() : 0); // <bytes in buffer; are these lost bytes that should be subtracted from __bytes_rx?>
276 stats->crypt_rx += r->__crypt_rx;
277 stats->crypt_tx += r->__crypt_tx;
278 stats->crypt_sx += r->__tls ? (r->__buffer != nullptr ? r->__buffer->get_utilized() : 0) : 0; // <bytes in buffer; are these lost bytes that should be subtracted from __crypt_rx?>
279 } // -x- if r.lock() -x-
280 } // -x- foreach __r -x-
281
282 return stats;
283 } // -x- std::unique_ptr<rsocket_io> net_io -x-
284
285 /*======================================================================*//**
286 @brief
287 Get combined total of socket I/O statistics from all rsocket objects in this
288 group as a pre-formatted std::string object.
289
290 See the @ref rsocket::net_io method for full documentation.
291
292 @par Threads
293 This method is threadsafe.
294 @returns An interpolated format string as an std::string object.
295 @see rsocket::net_io(const char*, size_t len)
296 *///=========================================================================
297 std::string net_io(
298 /// Format string
299 const char* format,
300 /// Length of format string (in bytes), or 0 to auto-detect length if format string is an ASCIIZ string
301 size_t len = 0) noexcept {
302 return rsocket().net_io(format, len, net_io().get()); // Call rsocket's net_io method on our internally-gathered group rsocket_io statistics
303 } // -x- std::string net_io -x-
304
305 private:
306 /*======================================================================*//**
307 @brief
308 Send data to all rsocket endpoints that are in this rsocket_group.
309 @par Threads
310 This method is threadsafe.
311 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
312 containing successful operations that also record the number of
313 bytes that were transmitted, and the second one containing failed
314 operations that also record the exception that was thrown (see the
315 @ref rsocket_group_rc structure for details)
316 @see rsocket::__send(void*, size_t, int)
317 *///=========================================================================
318 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& __send(
319 /// Data to send
320 const void* msg,
321 /// Number of bytes to send
322 const size_t len,
323 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
324 const int flags = 0) noexcept {
325
326 // --------------------------------------------------------------------------
327 // Internal variables.
328 // --------------------------------------------------------------------------
329 std::vector<rsocket_group_rc>* v1 = new std::vector<rsocket_group_rc>();
330 std::vector<rsocket_group_rc>* v2 = new std::vector<rsocket_group_rc>();
331 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>* pair = new std::pair(*v1, *v2);
332
333 // --------------------------------------------------------------------------
334 // Loop through all rsocket objects in the underlying std::set.
335 //
336 // We don't need a mutex lock here because the __send method is threadsafe.
337 // --------------------------------------------------------------------------
338 for (std::weak_ptr<rsocket> wp : __r) {
339 if (auto r = wp.lock()) { // Weak pointer is still valid, so acquire a std::unique_ptr while we access r
340 if (r->__debug) r->debug("rsocket_group::send(socket{0x" + randolf::rtools::to_hex(r->__socket_fd) + "}"
341 + ", <std::string>"
342 + ", " + std::to_string(len)
343 + ", " + std::to_string(flags)
344 + ");");
345 try {
346 v1->push_back({r.get(), r->__send(msg, len, flags), nullptr});
347 } catch (std::exception* e) {
348 v2->push_back({r.get(), 0, e});
349 }
350 } // -x- if r.lock() -x-
351 } // -x- foreach __r -x-
352
353 return *pair;
354 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& __send -x-
355
356 /*======================================================================*//**
357 @brief
358 Send data that included a final EoL sequence to all rsocket endpoints that
359 are in this rsocket_group.
360 @par Threads
361 This method is threadsafe.
362 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
363 containing successful operations that also record the number of
364 bytes that were transmitted, and the second one containing failed
365 operations that also record the exception that was thrown (see the
366 @ref rsocket_group_rc structure for details)
367 @see rsocket::__sendline(void*, size_t, int)
368 *///=========================================================================
369 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& __sendline(
370 /// Data to send
371 const void* msg,
372 /// Number of bytes to send
373 const size_t len,
374 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
375 const int flags = 0) noexcept {
376
377 // --------------------------------------------------------------------------
378 // Internal variables.
379 // --------------------------------------------------------------------------
380 std::vector<rsocket_group_rc>* v1 = new std::vector<rsocket_group_rc>();
381 std::vector<rsocket_group_rc>* v2 = new std::vector<rsocket_group_rc>();
382 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>* pair = new std::pair(*v1, *v2);
383
384 // --------------------------------------------------------------------------
385 // Loop through all rsocket objects in the underlying std::set.
386 //
387 // We don't need a mutex lock here because the __sendline method is
388 // threadsafe.
389 // --------------------------------------------------------------------------
390 for (std::weak_ptr<rsocket> wp : __r) {
391 if (auto r = wp.lock()) { // Weak pointer is still valid, so acquire a std::unique_ptr while we access r
392 if (r->__debug) r->debug("rsocket_group::send(socket{0x" + randolf::rtools::to_hex(r->__socket_fd) + "}"
393 + ", <std::string>"
394 + ", " + std::to_string(len)
395 + ", " + std::to_string(flags)
396 + ");");
397 try {
398 v1->push_back({r.get(), r->__sendline(msg, len, flags), nullptr});
399 } catch (std::exception* e) {
400 v2->push_back({r.get(), 0, e});
401 }
402 } // -x- if r.lock() -x-
403 } // -x- foreach __r -x-
404
405 return *pair;
406 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& __sendline -x-
407
408 /*======================================================================*//**
409 @brief
410 Send data that is the final EoL sequence to all rsocket endpoints that are in
411 this rsocket_group.
412 @par Threads
413 This method is threadsafe.
414 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
415 containing successful operations that also record the number of
416 bytes that were transmitted, and the second one containing failed
417 operations that also record the exception that was thrown (see the
418 @ref rsocket_group_rc structure for details)
419 @see rsocket::__sendline(void*, size_t, int)
420 *///=========================================================================
421 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& __send_eol(
422 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
423 const int flags = 0) noexcept {
424
425 // --------------------------------------------------------------------------
426 // Internal variables.
427 // --------------------------------------------------------------------------
428 std::vector<rsocket_group_rc>* v1 = new std::vector<rsocket_group_rc>();
429 std::vector<rsocket_group_rc>* v2 = new std::vector<rsocket_group_rc>();
430 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>* pair = new std::pair(*v1, *v2);
431
432 // --------------------------------------------------------------------------
433 // Loop through all rsocket objects in the underlying std::set.
434 //
435 // We don't need a mutex lock here because the __sendline method is
436 // threadsafe.
437 // --------------------------------------------------------------------------
438 for (std::weak_ptr<rsocket> wp : __r) {
439 if (auto r = wp.lock()) { // Weak pointer is still valid, so acquire a std::unique_ptr while we access r
440 if (r->__debug) r->debug("rsocket_group::send_eol(socket{0x" + randolf::rtools::to_hex(r->__socket_fd) + "}"
441 + ", " + std::to_string(flags)
442 + ");");
443 try {
444 v1->push_back({r.get(), r->__send_eol(flags), nullptr});
445 } catch (std::exception* e) {
446 v2->push_back({r.get(), 0, e});
447 }
448 } // -x- if r.lock() -x-
449 } // -x- foreach __r -x-
450
451 return *pair;
452 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& __send_eol -x-
453
454 public:
455 /*======================================================================*//**
456 @brief
457 Send data in the form of a std::string to all rsocket endpoints that are in
458 this rsocket_group.
459 @par Threads
460 This method is threadsafe.
461 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
462 containing successful operations that also record the number of
463 bytes that were transmitted, and the second one containing failed
464 operations that also record the exception that was thrown (see the
465 @ref rsocket_group_rc structure for details)
466 @see rsocket::send(const std::string, const int)
467 *///=========================================================================
468 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send(
469 /// Data to send
470 const std::string& msg,
471 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
472 const int flags = 0) {
473 return __send(msg.c_str(), msg.length(), flags);
474 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send -x-
475
476 /*======================================================================*//**
477 @brief
478 Send data in the form of a std::vector<char> to all rsocket endpoints that
479 are in this rsocket_group.
480 @par Threads
481 This method is threadsafe.
482 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
483 containing successful operations that also record the number of
484 bytes that were transmitted, and the second one containing failed
485 operations that also record the exception that was thrown (see the
486 @ref rsocket_group_rc structure for details)
487 @see rsocket::send(const std::vector<char>, const int)
488 *///=========================================================================
489 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send(
490 /// Data to send
491 const std::vector<char>& msg,
492 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
493 const int flags = 0) {
494 return __send(msg.data(), msg.size(), flags);
495 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send -x-
496
497 /*======================================================================*//**
498 @brief
499 Send data in the form of a C-string to all rsocket endpoints that are in this
500 rsocket_group.
501 @par Threads
502 This method is threadsafe.
503 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
504 containing successful operations that also record the number of
505 bytes that were transmitted, and the second one containing failed
506 operations that also record the exception that was thrown (see the
507 @ref rsocket_group_rc structure for details)
508 @see rsocket::send(const char*, const size_t, const int)
509 *///=========================================================================
510 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send(
511 /// Pointer to data to send
512 const char* msg,
513 /// Number of bytes to send
514 const size_t len,
515 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
516 const int flags = 0) {
517 return __send(msg, len, flags);
518 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send -x-
519
520 /*======================================================================*//**
521 @brief
522 Send data in the form of an ASCIIZ string to all rsocket endpoints that are
523 in this rsocket_group., including the terminating NULL character.
524 @par Threads
525 This method is threadsafe.
526 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
527 containing successful operations that also record the number of
528 bytes that were transmitted, and the second one containing failed
529 operations that also record the exception that was thrown (see the
530 @ref rsocket_group_rc structure for details)
531 @see sendz(const char*, const int) which doesn't transmit the terminating
532 NULL character
533 @see rsocket::send_asciiz(const char*, const int)
534 *///=========================================================================
535 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_asciiz(
536 /// Pointer to data to send
537 const char* msg,
538 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
539 const int flags = 0) {
540 return __send(msg, std::strlen(msg) + 1, flags);
541 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_asciiz -x-
542
543 /*======================================================================*//**
544 @brief
545 Send one byte of data to all rsocket endpoints that are in this
546 rsocket_group.
547 @par Threads
548 This method is threadsafe.
549 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
550 containing successful operations that also record the number of
551 bytes that were transmitted, and the second one containing failed
552 operations that also record the exception that was thrown (see the
553 @ref rsocket_group_rc structure for details)
554 @see rsocket::send_byte(const char, const int)
555 *///=========================================================================
556 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_byte(
557 /// Data to send
558 const char value,
559 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
560 const int flags = 0) {
561 return __send(&value, sizeof(value), flags);
562 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_byte -x-
563
564 /*======================================================================*//**
565 @brief
566 Send the EoL sequence to all rsocket endpoints that are in this
567 rsocket_group.
568 @par Threads
569 This method is threadsafe.
570 @returns The same rsocket object so as to facilitate stacking
571 *///=========================================================================
572 template <typename T> std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_eol(
573 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
574 const int flags = 0) {
575 return __send_eol(flags);
576 } // -x- template <typename T> std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_eol -x-
577
578 /*======================================================================*//**
579 @brief
580 Send one byte of data to all rsocket endpoints that are in this
581 rsocket_group.
582 @par Threads
583 This method is threadsafe.
584 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
585 containing successful operations that also record the number of
586 bytes that were transmitted, and the second one containing failed
587 operations that also record the exception that was thrown (see the
588 @ref rsocket_group_rc structure for details)
589 @see rsocket::send_struct(const T, const int)
590 *///=========================================================================
591 template <typename T> std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_struct(
592 /// Data to send
593 const T value,
594 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
595 const int flags = 0) {
596 return __send(&value, sizeof(value), flags);
597 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_struct -x-
598
599 /*======================================================================*//**
600 @brief
601 Send one 16-bit unsigned integer of data in LSB (little endian) order to all
602 rsocket endpoints that are in this rsocket_group.
603 @par Threads
604 This method is threadsafe.
605 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
606 containing successful operations that also record the number of
607 bytes that were transmitted, and the second one containing failed
608 operations that also record the exception that was thrown (see the
609 @ref rsocket_group_rc structure for details)
610 @see rsocket::send_uint16_lsb(const uint16_t, const int)
611 *///=========================================================================
612 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_uint16_lsb(
613 /// Data to send
614 const uint16_t value,
615 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
616 const int flags = 0) {
617 uint16_t buf = !__endian_is_msb ? value : ntohs(value);
618 return __send(&buf, sizeof(buf), flags);
619 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_uint16_lsb -x-
620
621 /*======================================================================*//**
622 @brief
623 Send one 16-bit integer of data in MSB (big endian) order to all rsocket
624 endpoints that are in this rsocket_group.
625 @par Threads
626 This method is threadsafe.
627 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
628 containing successful operations that also record the number of
629 bytes that were transmitted, and the second one containing failed
630 operations that also record the exception that was thrown (see the
631 @ref rsocket_group_rc structure for details)
632 @see rsocket::send_uint16_msb(const uint16_t, const int)
633 *///=========================================================================
634 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_uint16_msb(
635 /// Data to send
636 const uint16_t value,
637 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
638 const int flags = 0) {
639 int16_t buf = __endian_is_msb ? value : htons(value);
640 return __send(&buf, sizeof(buf), flags);
641 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_int16_msb -x-
642
643 /*======================================================================*//**
644 @brief
645 Send one 32-bit unsigned integer of data in LSB (little endian) order to all
646 rsocket endpoints that are in this rsocket_group.
647 @par Threads
648 This method is threadsafe.
649 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
650 containing successful operations that also record the number of
651 bytes that were transmitted, and the second one containing failed
652 operations that also record the exception that was thrown (see the
653 @ref rsocket_group_rc structure for details)
654 @see rsocket::send_uint32_lsb(const uint32_t, const int)
655 *///=========================================================================
656 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_uint32_lsb(
657 /// Data to send
658 const uint32_t value,
659 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
660 const int flags = 0) {
661 uint32_t buf = !__endian_is_msb ? value : ntohl(value);
662 return __send(&buf, sizeof(buf), flags);
663 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_uint32_lsb -x-
664
665 /*======================================================================*//**
666 @brief
667 Send one 32-bit unsigned integer of data in MSB (big endian) order to all
668 rsocket endpoints that are in this rsocket_group.
669 @par Threads
670 This method is threadsafe.
671 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
672 containing successful operations that also record the number of
673 bytes that were transmitted, and the second one containing failed
674 operations that also record the exception that was thrown (see the
675 @ref rsocket_group_rc structure for details)
676 @see rsocket::send_uint32_msb(const uint32_t, const int)
677 *///=========================================================================
678 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_uint32_msb(
679 /// Data to send
680 const uint32_t value,
681 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
682 const int flags = 0) {
683 uint32_t buf = __endian_is_msb ? value : htonl(value);
684 return __send(&buf, sizeof(buf), flags);
685 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_uint32_msb -x-
686
687 /*======================================================================*//**
688 @brief
689 Send one 64-bit unsigned integer of data in LSB (little endian) order to all
690 rsocket endpoints that are in this rsocket_group.
691 @par Threads
692 This method is threadsafe.
693 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
694 containing successful operations that also record the number of
695 bytes that were transmitted, and the second one containing failed
696 operations that also record the exception that was thrown (see the
697 @ref rsocket_group_rc structure for details)
698 @see rsocket::send_uint64_lsb(const uint64_t, const int)
699 *///=========================================================================
700 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_uint64_lsb(
701 /// Data to send
702 const uint64_t value,
703 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
704 const int flags = 0) {
705 uint64_t buf = !__endian_is_msb ? value : ((((uint64_t)ntohl((value) & 0xffffffffUL)) << 32) | ntohl((uint32_t)((value) >> 32)));
706 return __send(&buf, sizeof(buf), flags);
707 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_uint64_lsb -x-
708
709 /*======================================================================*//**
710 @brief
711 Send one 64-bit unsigned integer of data in MSB (big endian) order to all
712 rsocket endpoints that are in this rsocket_group.
713 @par Threads
714 This method is threadsafe.
715 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
716 containing successful operations that also record the number of
717 bytes that were transmitted, and the second one containing failed
718 operations that also record the exception that was thrown (see the
719 @ref rsocket_group_rc structure for details)
720 @see rsocket::send_uint64_msb(const uint64_t, const int)
721 *///=========================================================================
722 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_uint64_msb(
723 /// Data to send
724 const uint64_t value,
725 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
726 const int flags = 0) {
727 uint64_t buf = __endian_is_msb ? value : ((((uint64_t)htonl((value) & 0xffffffffUL)) << 32) | htonl((uint32_t)((value) >> 32)));
728 return __send(&buf, sizeof(buf), flags);
729 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& send_uint64_msb -x-
730
731 /*======================================================================*//**
732 @brief
733 Send data in the form of a std::string to all rsocket endpoints that are in
734 this rsocket_group, with an EoL sequence appended.
735 @returns The same rsocket object so as to facilitate stacking
736 @par Threads
737 This method is threadsafe.
738 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
739 containing successful operations that also record the number of
740 bytes that were transmitted, and the second one containing failed
741 operations that also record the exception that was thrown (see the
742 @ref rsocket_group_rc structure for details)
743 @see recvline(const size_t, const int)
744 @see rsocket::sendline(const std::string, const int)
745 *///=========================================================================
746 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& sendline(
747 /// Data to send
748 const std::string& msg = std::string(),
749 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
750 const int flags = 0) {
751 return __sendline(msg.c_str(), msg.length(), flags);
752 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& sendline -x-
753
754 /*======================================================================*//**
755 @brief
756 Send data in the form of an ASCIIZ string to all rsocket endpoints that are
757 in this rsocket_group.. The terminating NULL character won't be transmitted.
758 @par Threads
759 This method is threadsafe.
760 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
761 containing successful operations that also record the number of
762 bytes that were transmitted, and the second one containing failed
763 operations that also record the exception that was thrown (see the
764 @ref rsocket_group_rc structure for details)
765 @see send_asciiz which also transmits the terminating NULL character
766 @see rsocket::sendz(const char*, const int)
767 *///=========================================================================
768 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& sendz(
769 /// Pointer to data to send
770 const char* msg,
771 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
772 const int flags = 0) {
773 return __send(msg, std::strlen(msg), flags);
774 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& sendz -x-
775
776 /*======================================================================*//**
777 @brief
778 Shut down the underlying sockets in all rsocket objects that are in this
779 rsocket_group, partially or fully.
780
781 SHUT_RD: Further receives will be disallowed
782 SHUT_WR: Further sends will be disallowed (this may cause actions
783 specific to the protocol family of the socket to occur)
784 SHUT_RDWR: Further sends and receives will be disallowed (default)
785 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
786 containing successful operations that also record the number of
787 bytes that were transmitted, and the second one containing failed
788 operations that also record the exception that was thrown (see the
789 @ref rsocket_group_rc structure for details)
790 @see rsocket::shutdown(const int)
791 *///=========================================================================
792 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& shutdown(
793 /// SHUT_RD@n SHUT_RW@n SHUT_RDWR
794 const int how = SHUT_RDWR) {
795
796 // --------------------------------------------------------------------------
797 // Internal variables.
798 // --------------------------------------------------------------------------
799 std::vector<rsocket_group_rc>* v1 = new std::vector<rsocket_group_rc>();
800 std::vector<rsocket_group_rc>* v2 = new std::vector<rsocket_group_rc>();
801 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>* pair = new std::pair(*v1, *v2);
802
803 // --------------------------------------------------------------------------
804 // Loop through all rsocket objects in the underlying std::set.
805 //
806 // We don't need a mutex lock here because the shutdown method is threadsafe.
807 // --------------------------------------------------------------------------
808 for (std::weak_ptr<rsocket> wp : __r) {
809 if (auto r = wp.lock()) { // Weak pointer is still valid, so acquire a std::unique_ptr while we access r
810 try {
811 r->shutdown(how);
812 v1->push_back({r.get(), 0, nullptr});
813 } catch (std::exception* e) {
814 v2->push_back({r.get(), 0, e});
815 }
816 } // -x- if r.lock() -x-
817 } // -x- foreach __r -x-
818
819 return *pair;
820 } // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>>& shutdown -x-
821
822 /*======================================================================*//**
823 @brief
824 Find out how many rsocket entries are in this group.
825
826 @par Threads
827 This method is threadsafe.
828 @returns Number of rsocket objects in the underlying std::set
829 *///=========================================================================
830 size_t size() noexcept {
831 const std::lock_guard<std::mutex> lock(__mutex);
832 return __r.size();
833 } // -x- size_t size -x-
834
835 }; // -x- class rsocket_group -x-
836
837}; // -x- namespace randolf -x-