3//#include <randolf/rex>
4//#include <randolf/rsocket>
5#include <randolf/rsocket_group_rc>
6#include <randolf/rtools>
10 /*======================================================================*//**
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.
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.
20 This class is threadsafe.
21 @author Randolf Richardson
24 2022-Dec-29 v1.00 Initial version
25 *///=========================================================================
29 // --------------------------------------------------------------------------
30 // Comparator for use with std::set<rsocket> initialization. It simply
31 // compares the physical address of the instantiated rsocket() object since
32 // this is immediately available for the fastest possible comparison.
33 // --------------------------------------------------------------------------
34 template<typename R> struct __rsocket_cmp {
35 bool operator() (const std::weak_ptr<rsocket> r1, const std::weak_ptr<rsocket> r2) const {
36 auto _r1 = r1.lock(); if (!_r1) return false; // Expired pointer; we're done
37 auto _r2 = r2.lock(); if (!_r1) return true; // Not expired-after-expired pointer
38 return (uintptr_t)_r1.get() < (uintptr_t)_r2.get(); // Compare pointers as uint values
39 } // -x- bool operator() -x-
40 }; // -x- struct __rsocket_cmp -x-
42 // --------------------------------------------------------------------------
43 // Internal variables.
44 // --------------------------------------------------------------------------
45 std::mutex __mutex; // Used to ensure thread safety
46 std::set<std::weak_ptr<rsocket>, __rsocket_cmp<rsocket>> __r; // Set of rsocket objects (with our comparator)
48 // --------------------------------------------------------------------------
49 // Keep track of test for whether this host stores integers using big endian.
50 // --------------------------------------------------------------------------
51 inline static const bool __endian_is_msb = htons(42) == 42; // TRUE==MSB / FALSE==LSB
53 // --------------------------------------------------------------------------
54 // General variables. Atomic variables are used for variables as needed to
55 // support operations in a thread-safe manner.
56 // --------------------------------------------------------------------------
60 /*======================================================================*//**
62 Instantiate an rsocket group with no @ref rsocket objects.
65 *///=========================================================================
66 rsocket_group() noexcept {}; // -x- constructor rsocket_group -x-
68 /*======================================================================*//**
70 Instantiate an rsocket group with any number of @ref rsocket objects.
73 *///=========================================================================
74 template<class R, class... Rs> rsocket_group(
75 /// Pointer to instantiated rsocket object
77 /// Variadic arguments (any quantity of instantiated rsocket objects)
81 }; // -x- constructor rsocket_group -x-
84 /*======================================================================*//**
86 Internal method that is used by the @ref insert(rsocket*) method.
89 This method is not threadsafe.
90 *///=========================================================================
92 /// Pointer to instantiated rsocket object
93 rsocket* r) noexcept {
94 if (r == nullptr) return;
95 __r.insert(std::make_shared<rsocket>(r)); // Effectively: std::make_weak()
96 }; // -x- void __insert -x-
98 /*======================================================================*//**
100 Internal method that is used by the @ref insert(rsocket*, ...) method.
103 This method is not threadsafe.
104 *///=========================================================================
105 template<class R, class... Rs> void __insert(
106 /// Pointer to instantiated rsocket object
108 /// Variadic arguments (any quantity of instantiated rsocket objects)
112 }; // -x- void __insert -x-
115 /*======================================================================*//**
117 Close all rsocketss that are in this rsocket_group.
118 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
119 containing successful operations that also record the number of
120 bytes that were transmitted, and the second one containing failed
121 operations that also record the exception that was thrown (see the
122 @ref rsocket_group_rc structure for details)
123 @see rsocket::close()
124 *///=========================================================================
125 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> close() {
127 // --------------------------------------------------------------------------
128 // Internal variables.
129 // --------------------------------------------------------------------------
130 std::vector<rsocket_group_rc> v1;
131 std::vector<rsocket_group_rc> v2;
133 // --------------------------------------------------------------------------
134 // Loop through all rsocket objects in the underlying std::set.
136 // We don't need a mutex lock here because the close() method is threadsafe.
137 // --------------------------------------------------------------------------
138 for (std::weak_ptr<rsocket> wp : __r) {
139 if (auto r = wp.lock()) { // Weak pointer is still valid, so acquire a std::shared_ptr while we access r
142 v1.push_back({r.get(), 0, nullptr});
143 } catch (std::exception* e) {
144 v2.push_back({r.get(), 0, e});
146 } // -x- if r.lock() -x-
147 } // -x- foreach __r -x-
149 return std::pair(v1, v2);
150 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> shutdown -x-
152 /*======================================================================*//**
154 Remove an rsocket object from the underlying std::set.
157 This method is threadsafe.
158 *///=========================================================================
160 /// Pointer to instantiated rsocket object
162 const std::lock_guard<std::mutex> lock(__mutex);
163 __r.erase(std::make_shared<rsocket>(r)); // Effectively: std::make_weak()
164 }; // -x- void erase -x-
166 /*======================================================================*//**
168 Add one rsocket object to the underlying std::set.
171 This method is threadsafe.
172 *///=========================================================================
174 /// Pointer to instantiated rsocket object
176 const std::lock_guard<std::mutex> lock(__mutex);
178 }; // -x- void insert -x-
180 /*======================================================================*//**
182 Add one or more rsocket objects to the underlying std::set.
185 This method is threadsafe.
186 *///=========================================================================
187 template<class R, class... Rs> void insert(
188 /// Pointer to instantiated rsocket object
190 /// Variadic arguments (any quantity of instantiated rsocket objects)
192 const std::lock_guard<std::mutex> lock(__mutex);
195 }; // -x- void insert -x-
197 /*======================================================================*//**
199 Specify a name for this rsocket_group.
201 This is an arbitrary name that is entirely optional, and should be regarded
202 as similar to the naming of threads.
205 This method is threadsafe.
206 *///=========================================================================
208 /// Name to assign to this rsocket_group
209 const std::string name) noexcept {
210 const std::lock_guard<std::mutex> lock(__mutex);
212 }; // -x- void name -x-
214 /*======================================================================*//**
216 Find out what this rsocket_group's name is.
219 This method is threadsafe.
220 @returns The name of this rsocket (or an empty std::string if this rsocket
222 *///=========================================================================
223 std::string name() noexcept {
224 const std::lock_guard<std::mutex> lock(__mutex);
226 }; // -x- std::string name -x-
228 /*======================================================================*//**
230 Get the combined total of socket I/O statistics from all rsocket objects in
233 The number of bytes transmitted and received is tracked internally, so that
234 the information can be used later in logging. These statistics are available
235 at all times, but for logging purposes it makes the most sense to copy this
236 information after the rsocket is closed, at which time the final statistics
237 will continue to be available until the rsocket's destructor takes over.
240 This method is threadsafe.
241 @returns rsocket_io wrapped in a std::shared_ptr object to help ease memory
243 @see rsocket::net_io()
244 *///=========================================================================
245 std::shared_ptr<rsocket_io> net_io() noexcept {
246 std::shared_ptr stats = std::make_shared<rsocket_io>();
248 // --------------------------------------------------------------------------
249 // Loop through all rsocket objects in the underlying std::set.
251 // We don't need a mutex lock here because the stastical rx/tx counters in
252 // every rsocket class are atomic variables.
253 // --------------------------------------------------------------------------
254 for (std::weak_ptr<rsocket> wp : __r) {
255 if (auto r = wp.lock()) { // Weak pointer is still valid, so acquire a std::shared_ptr while we access r
256 stats->bytes_rx += r->__bytes_rx;
257 stats->bytes_tx += r->__bytes_tx;
258 stats->crypt_rx += r->__crypt_rx;
259 stats->crypt_tx += r->__crypt_tx;
260 } // -x- if r.lock() -x-
261 } // -x- foreach __r -x-
264 }; // -x- std::shared_ptr<rsocket_io> net_io -x-
266 /*======================================================================*//**
268 Get combined total of socket I/O statistics from all rsocket objects in this
269 group as a pre-formatted std::string object.
271 See the @ref rsocket::net_io method for full documentation.
274 This method is threadsafe.
275 @returns An interpolated format string as an std::string object.
276 @see rsocket::net_io(const char*, size_t len)
277 *///=========================================================================
281 /// Length of format string (in bytes), or 0 to auto-detect length if format string is an ASCIIZ string
282 size_t len = 0) noexcept {
283 return rsocket().net_io(format, len, net_io().get()); // Call rsocket's net_io method on our internally-gathered group rsocket_io statistics
284 }; // -x- std::string net_io -x-
287 /*======================================================================*//**
289 Send data to all rsocket endpoints that are in this rsocket_group.
291 This method is threadsafe.
292 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
293 containing successful operations that also record the number of
294 bytes that were transmitted, and the second one containing failed
295 operations that also record the exception that was thrown (see the
296 @ref rsocket_group_rc structure for details)
297 @see rsocket::__send(void*, size_t, int)
298 *///=========================================================================
299 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> __send(
302 /// Number of bytes to send
304 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
305 const int flags = 0) noexcept {
307 // --------------------------------------------------------------------------
308 // Internal variables.
309 // --------------------------------------------------------------------------
310 std::vector<rsocket_group_rc> v1;
311 std::vector<rsocket_group_rc> v2;
313 // --------------------------------------------------------------------------
314 // Loop through all rsocket objects in the underlying std::set.
316 // We don't need a mutex lock here because the __send method is threadsafe.
317 // --------------------------------------------------------------------------
318 for (std::weak_ptr<rsocket> wp : __r) {
319 if (auto r = wp.lock()) { // Weak pointer is still valid, so acquire a std::shared_ptr while we access r
320 if (r->__debug) r->debug("rsocket_group::send(socket{0x" + randolf::rtools::to_hex(r->__socket_fd) + "}"
322 + ", " + std::to_string(len)
323 + ", " + std::to_string(flags)
326 v1.push_back({r.get(), r->__send(msg, len, flags), nullptr});
327 } catch (std::exception* e) {
328 v2.push_back({r.get(), 0, e});
330 } // -x- if r.lock() -x-
331 } // -x- foreach __r -x-
333 return std::pair(v1, v2);
334 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> __send -x-
336 /*======================================================================*//**
338 Send data that included a final EoL sequence to all rsocket endpoints that
339 are in this rsocket_group.
341 This method is threadsafe.
342 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
343 containing successful operations that also record the number of
344 bytes that were transmitted, and the second one containing failed
345 operations that also record the exception that was thrown (see the
346 @ref rsocket_group_rc structure for details)
347 @see rsocket::__sendline(void*, size_t, int)
348 *///=========================================================================
349 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> __sendline(
352 /// Number of bytes to send
354 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
355 const int flags = 0) noexcept {
357 // --------------------------------------------------------------------------
358 // Internal variables.
359 // --------------------------------------------------------------------------
360 std::vector<rsocket_group_rc> v1;
361 std::vector<rsocket_group_rc> v2;
363 // --------------------------------------------------------------------------
364 // Loop through all rsocket objects in the underlying std::set.
366 // We don't need a mutex lock here because the __sendline method is
368 // --------------------------------------------------------------------------
369 for (std::weak_ptr<rsocket> wp : __r) {
370 if (auto r = wp.lock()) { // Weak pointer is still valid, so acquire a std::shared_ptr while we access r
371 if (r->__debug) r->debug("rsocket_group::send(socket{0x" + randolf::rtools::to_hex(r->__socket_fd) + "}"
373 + ", " + std::to_string(len)
374 + ", " + std::to_string(flags)
377 v1.push_back({r.get(), r->__sendline(msg, len, flags), nullptr});
378 } catch (std::exception* e) {
379 v2.push_back({r.get(), 0, e});
381 } // -x- if r.lock() -x-
382 } // -x- foreach __r -x-
384 return std::pair(v1, v2);
385 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> __sendline -x-
387 /*======================================================================*//**
389 Send data that is the final EoL sequence to all rsocket endpoints that are in
392 This method is threadsafe.
393 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
394 containing successful operations that also record the number of
395 bytes that were transmitted, and the second one containing failed
396 operations that also record the exception that was thrown (see the
397 @ref rsocket_group_rc structure for details)
398 @see rsocket::__sendline(void*, size_t, int)
399 *///=========================================================================
400 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> __send_eol(
401 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
402 const int flags = 0) noexcept {
404 // --------------------------------------------------------------------------
405 // Internal variables.
406 // --------------------------------------------------------------------------
407 std::vector<rsocket_group_rc> v1;
408 std::vector<rsocket_group_rc> v2;
410 // --------------------------------------------------------------------------
411 // Loop through all rsocket objects in the underlying std::set.
413 // We don't need a mutex lock here because the __sendline method is
415 // --------------------------------------------------------------------------
416 for (std::weak_ptr<rsocket> wp : __r) {
417 if (auto r = wp.lock()) { // Weak pointer is still valid, so acquire a std::shared_ptr while we access r
418 if (r->__debug) r->debug("rsocket_group::send_eol(socket{0x" + randolf::rtools::to_hex(r->__socket_fd) + "}"
419 + ", " + std::to_string(flags)
422 v1.push_back({r.get(), r->__send_eol(flags), nullptr});
423 } catch (std::exception* e) {
424 v2.push_back({r.get(), 0, e});
426 } // -x- if r.lock() -x-
427 } // -x- foreach __r -x-
429 return std::pair(v1, v2);
430 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> __send_eol -x-
433 /*======================================================================*//**
435 Send data in the form of a std::string to all rsocket endpoints that are in
438 This method is threadsafe.
439 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
440 containing successful operations that also record the number of
441 bytes that were transmitted, and the second one containing failed
442 operations that also record the exception that was thrown (see the
443 @ref rsocket_group_rc structure for details)
444 @see rsocket::send(const std::string, const int)
445 *///=========================================================================
446 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send(
448 const std::string msg,
449 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
450 const int flags = 0) {
451 return __send(msg.c_str(), msg.length(), flags);
452 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send -x-
454 /*======================================================================*//**
456 Send data in the form of a std::vector<char> to all rsocket endpoints that
457 are in this rsocket_group.
459 This method is threadsafe.
460 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
461 containing successful operations that also record the number of
462 bytes that were transmitted, and the second one containing failed
463 operations that also record the exception that was thrown (see the
464 @ref rsocket_group_rc structure for details)
465 @see rsocket::send(const std::vector<char>, const int)
466 *///=========================================================================
467 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send(
469 const std::vector<char> msg,
470 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
471 const int flags = 0) {
472 return __send(msg.data(), msg.size(), flags);
473 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send -x-
475 /*======================================================================*//**
477 Send data in the form of a C-string to all rsocket endpoints that are in this
480 This method is threadsafe.
481 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
482 containing successful operations that also record the number of
483 bytes that were transmitted, and the second one containing failed
484 operations that also record the exception that was thrown (see the
485 @ref rsocket_group_rc structure for details)
486 @see rsocket::send(const char*, const size_t, const int)
487 *///=========================================================================
488 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send(
489 /// Pointer to data to send
491 /// Number of bytes to send
493 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
494 const int flags = 0) {
495 return __send(msg, len, flags);
496 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send -x-
498 /*======================================================================*//**
500 Send data in the form of an ASCIIZ string to all rsocket endpoints that are
501 in this rsocket_group., including the terminating NULL character.
503 This method is threadsafe.
504 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
505 containing successful operations that also record the number of
506 bytes that were transmitted, and the second one containing failed
507 operations that also record the exception that was thrown (see the
508 @ref rsocket_group_rc structure for details)
509 @see sendz(const char*, const int) which doesn't transmit the terminating
511 @see rsocket::send_asciiz(const char*, const int)
512 *///=========================================================================
513 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_asciiz(
514 /// Pointer to data to send
516 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
517 const int flags = 0) {
518 return __send(msg, std::strlen(msg) + 1, flags);
519 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_asciiz -x-
521 /*======================================================================*//**
523 Send one byte of data to all rsocket endpoints that are in this
526 This method is threadsafe.
527 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
528 containing successful operations that also record the number of
529 bytes that were transmitted, and the second one containing failed
530 operations that also record the exception that was thrown (see the
531 @ref rsocket_group_rc structure for details)
532 @see rsocket::send_byte(const char, const int)
533 *///=========================================================================
534 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_byte(
537 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
538 const int flags = 0) {
539 return __send(&value, sizeof(value), flags);
540 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_byte -x-
542 /*======================================================================*//**
544 Send the EoL sequence to all rsocket endpoints that are in this
547 This method is threadsafe.
548 @returns The same rsocket object so as to facilitate stacking
549 *///=========================================================================
550 template <typename T> std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_eol(
551 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
552 const int flags = 0) {
553 return __send_eol(flags);
554 }; // -x- template <typename T> std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_eol -x-
556 /*======================================================================*//**
558 Send one byte of data to all rsocket endpoints that are in this
561 This method is threadsafe.
562 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
563 containing successful operations that also record the number of
564 bytes that were transmitted, and the second one containing failed
565 operations that also record the exception that was thrown (see the
566 @ref rsocket_group_rc structure for details)
567 @see rsocket::send_struct(const T, const int)
568 *///=========================================================================
569 template <typename T> std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_struct(
572 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
573 const int flags = 0) {
574 return __send(&value, sizeof(value), flags);
575 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_struct -x-
577 /*======================================================================*//**
579 Send one 16-bit unsigned integer of data in LSB (little endian) order to all
580 rsocket endpoints that are in this rsocket_group.
582 This method is threadsafe.
583 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
584 containing successful operations that also record the number of
585 bytes that were transmitted, and the second one containing failed
586 operations that also record the exception that was thrown (see the
587 @ref rsocket_group_rc structure for details)
588 @see rsocket::send_uint16_lsb(const uint16_t, const int)
589 *///=========================================================================
590 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint16_lsb(
592 const uint16_t value,
593 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
594 const int flags = 0) {
595 uint16_t buf = !__endian_is_msb ? value : ntohs(value);
596 return __send(&buf, sizeof(buf), flags);
597 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint16_lsb -x-
599 /*======================================================================*//**
601 Send one 16-bit integer of data in MSB (big endian) order to all rsocket
602 endpoints that are in this rsocket_group.
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_msb(const uint16_t, const int)
611 *///=========================================================================
612 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint16_msb(
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 int16_t buf = __endian_is_msb ? value : htons(value);
618 return __send(&buf, sizeof(buf), flags);
619 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_int16_msb -x-
621 /*======================================================================*//**
623 Send one 32-bit unsigned integer of data in LSB (little endian) order to all
624 rsocket endpoints that are in this rsocket_group.
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_uint32_lsb(const uint32_t, const int)
633 *///=========================================================================
634 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint32_lsb(
636 const uint32_t value,
637 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
638 const int flags = 0) {
639 uint32_t buf = !__endian_is_msb ? value : ntohl(value);
640 return __send(&buf, sizeof(buf), flags);
641 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint32_lsb -x-
643 /*======================================================================*//**
645 Send one 32-bit unsigned integer of data in MSB (big endian) order to all
646 rsocket endpoints that are in this rsocket_group.
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_msb(const uint32_t, const int)
655 *///=========================================================================
656 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint32_msb(
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 : htonl(value);
662 return __send(&buf, sizeof(buf), flags);
663 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint32_msb -x-
665 /*======================================================================*//**
667 Send one 64-bit unsigned integer of data in LSB (little endian) order to all
668 rsocket endpoints that are in this rsocket_group.
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_uint64_lsb(const uint64_t, const int)
677 *///=========================================================================
678 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint64_lsb(
680 const uint64_t value,
681 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
682 const int flags = 0) {
683 uint64_t buf = !__endian_is_msb ? value : ((((uint64_t)ntohl((value) & 0xffffffffUL)) << 32) | ntohl((uint32_t)((value) >> 32)));
684 return __send(&buf, sizeof(buf), flags);
685 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint64_lsb -x-
687 /*======================================================================*//**
689 Send one 64-bit unsigned integer of data in MSB (big endian) order to all
690 rsocket endpoints that are in this rsocket_group.
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_msb(const uint64_t, const int)
699 *///=========================================================================
700 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint64_msb(
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)htonl((value) & 0xffffffffUL)) << 32) | htonl((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_msb -x-
709 /*======================================================================*//**
711 Send data in the form of a std::string to all rsocket endpoints that are in
712 this rsocket_group, with an EoL sequence appended.
713 @returns The same rsocket object so as to facilitate stacking
715 This method is threadsafe.
716 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
717 containing successful operations that also record the number of
718 bytes that were transmitted, and the second one containing failed
719 operations that also record the exception that was thrown (see the
720 @ref rsocket_group_rc structure for details)
721 @see recvline(const size_t, const int)
722 @see rsocket::sendline(const std::string, const int)
723 *///=========================================================================
724 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> sendline(
726 const std::string msg = std::string(),
727 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
728 const int flags = 0) {
729 return __sendline(msg.c_str(), msg.length(), flags);
730 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> sendline -x-
732 /*======================================================================*//**
734 Send data in the form of an ASCIIZ string to all rsocket endpoints that are
735 in this rsocket_group.. The terminating NULL character won't be transmitted.
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 send_asciiz which also transmits the terminating NULL character
744 @see rsocket::sendz(const char*, const int)
745 *///=========================================================================
746 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> sendz(
747 /// Pointer to data to send
749 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
750 const int flags = 0) {
751 return __send(msg, std::strlen(msg), flags);
752 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> sendz -x-
754 /*======================================================================*//**
756 Shut down the underlying sockets in all rsocket objects that are in this
757 rsocket_group, partially or fully.
759 SHUT_RD: Further receives will be disallowed
760 SHUT_WR: Further sends will be disallowed (this may cause actions
761 specific to the protocol family of the socket to occur)
762 SHUT_RDWR: Further sends and receives will be disallowed (default)
763 @returns A std::pair of std::vector<rsocket_group_rc> vectors, the first one
764 containing successful operations that also record the number of
765 bytes that were transmitted, and the second one containing failed
766 operations that also record the exception that was thrown (see the
767 @ref rsocket_group_rc structure for details)
768 @see rsocket::shutdown(const int)
769 *///=========================================================================
770 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> shutdown(
771 /// SHUT_RD@n SHUT_RW@n SHUT_RDWR
772 const int how = SHUT_RDWR) {
774 // --------------------------------------------------------------------------
775 // Internal variables.
776 // --------------------------------------------------------------------------
777 std::vector<rsocket_group_rc> v1;
778 std::vector<rsocket_group_rc> v2;
780 // --------------------------------------------------------------------------
781 // Loop through all rsocket objects in the underlying std::set.
783 // We don't need a mutex lock here because the shutdown method is threadsafe.
784 // --------------------------------------------------------------------------
785 for (std::weak_ptr<rsocket> wp : __r) {
786 if (auto r = wp.lock()) { // Weak pointer is still valid, so acquire a std::shared_ptr while we access r
789 v1.push_back({r.get(), 0, nullptr});
790 } catch (std::exception* e) {
791 v2.push_back({r.get(), 0, e});
793 } // -x- if r.lock() -x-
794 } // -x- foreach __r -x-
796 return std::pair(v1, v2);
797 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> shutdown -x-
799 /*======================================================================*//**
801 Find out how many rsocket entries are in this group.
804 This method is threadsafe.
805 @returns Number of rsocket objects in the underlying std::set
806 *///=========================================================================
808 const std::lock_guard<std::mutex> lock(__mutex);
810 }; // -x- size_t size -x-
812 }; // -x- class rsocket_group -x-
814}; // -x- namespace randolf -x-