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 *///=========================================================================
26 class rsocket_group {
27
28 private:
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-
41
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)
47
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
52
53 // --------------------------------------------------------------------------
54 // General variables. Atomic variables are used for variables as needed to
55 // support operations in a thread-safe manner.
56 // --------------------------------------------------------------------------
57 std::string __name;
58
59 public:
60 /*======================================================================*//**
61 @brief
62 Instantiate an rsocket group with no @ref rsocket objects.
63
64 @see insert()
65 *///=========================================================================
66 rsocket_group() noexcept {}; // -x- constructor rsocket_group -x-
67
68 /*======================================================================*//**
69 @brief
70 Instantiate an rsocket group with any number of @ref rsocket objects.
71
72 @see insert()
73 *///=========================================================================
74 template<class R, class... Rs> rsocket_group(
75 /// Pointer to instantiated rsocket object
76 R r,
77 /// Variadic arguments (any quantity of instantiated rsocket objects)
78 Rs... rs) noexcept {
79 __insert(r);
80 __insert(rs...);
81 }; // -x- constructor rsocket_group -x-
82
83 private:
84 /*======================================================================*//**
85 @brief
86 Internal method that is used by the @ref insert(rsocket*) method.
87
88 @warning
89 This method is not threadsafe.
90 *///=========================================================================
91 void __insert(
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-
97
98 /*======================================================================*//**
99 @brief
100 Internal method that is used by the @ref insert(rsocket*, ...) method.
101
102 @warning
103 This method is not threadsafe.
104 *///=========================================================================
105 template<class R, class... Rs> void __insert(
106 /// Pointer to instantiated rsocket object
107 R r,
108 /// Variadic arguments (any quantity of instantiated rsocket objects)
109 Rs... rs) noexcept {
110 __insert(r);
111 __insert(rs...);
112 }; // -x- void __insert -x-
113
114 public:
115 /*======================================================================*//**
116 @brief
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() {
126
127 // --------------------------------------------------------------------------
128 // Internal variables.
129 // --------------------------------------------------------------------------
130 std::vector<rsocket_group_rc> v1;
131 std::vector<rsocket_group_rc> v2;
132
133 // --------------------------------------------------------------------------
134 // Loop through all rsocket objects in the underlying std::set.
135 //
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
140 try {
141 r->close();
142 v1.push_back({r.get(), 0, nullptr});
143 } catch (std::exception* e) {
144 v2.push_back({r.get(), 0, e});
145 }
146 } // -x- if r.lock() -x-
147 } // -x- foreach __r -x-
148
149 return std::pair(v1, v2);
150 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> shutdown -x-
151
152 /*======================================================================*//**
153 @brief
154 Remove an rsocket object from the underlying std::set.
155
156 @par Threads
157 This method is threadsafe.
158 *///=========================================================================
159 void erase(
160 /// Pointer to instantiated rsocket object
161 rsocket* r) {
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-
165
166 /*======================================================================*//**
167 @brief
168 Add one rsocket object to the underlying std::set.
169
170 @par Threads
171 This method is threadsafe.
172 *///=========================================================================
173 void insert(
174 /// Pointer to instantiated rsocket object
175 rsocket* r) {
176 const std::lock_guard<std::mutex> lock(__mutex);
177 __insert(r);
178 }; // -x- void insert -x-
179
180 /*======================================================================*//**
181 @brief
182 Add one or more rsocket objects to the underlying std::set.
183
184 @par Threads
185 This method is threadsafe.
186 *///=========================================================================
187 template<class R, class... Rs> void insert(
188 /// Pointer to instantiated rsocket object
189 R r,
190 /// Variadic arguments (any quantity of instantiated rsocket objects)
191 Rs... rs) {
192 const std::lock_guard<std::mutex> lock(__mutex);
193 __insert(r);
194 __insert(rs...);
195 }; // -x- void insert -x-
196
197 /*======================================================================*//**
198 @brief
199 Specify a name for this rsocket_group.
200
201 This is an arbitrary name that is entirely optional, and should be regarded
202 as similar to the naming of threads.
203
204 @par Threads
205 This method is threadsafe.
206 *///=========================================================================
207 void name(
208 /// Name to assign to this rsocket_group
209 const std::string name) noexcept {
210 const std::lock_guard<std::mutex> lock(__mutex);
211 __name = name;
212 }; // -x- void name -x-
213
214 /*======================================================================*//**
215 @brief
216 Find out what this rsocket_group's name is.
217
218 @par Threads
219 This method is threadsafe.
220 @returns The name of this rsocket (or an empty std::string if this rsocket
221 doesn't have a name)
222 *///=========================================================================
223 std::string name() noexcept {
224 const std::lock_guard<std::mutex> lock(__mutex);
225 return __name;
226 }; // -x- std::string name -x-
227
228 /*======================================================================*//**
229 @brief
230 Get the combined total of socket I/O statistics from all rsocket objects in
231 this group.
232
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.
238
239 @par Threads
240 This method is threadsafe.
241 @returns rsocket_io wrapped in a std::shared_ptr object to help ease memory
242 management efforts
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>();
247
248 // --------------------------------------------------------------------------
249 // Loop through all rsocket objects in the underlying std::set.
250 //
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-
262
263 return stats;
264 }; // -x- std::shared_ptr<rsocket_io> net_io -x-
265
266 /*======================================================================*//**
267 @brief
268 Get combined total of socket I/O statistics from all rsocket objects in this
269 group as a pre-formatted std::string object.
270
271 See the @ref rsocket::net_io method for full documentation.
272
273 @par Threads
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 *///=========================================================================
278 std::string net_io(
279 /// Format string
280 const char* format,
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-
285
286 private:
287 /*======================================================================*//**
288 @brief
289 Send data to all rsocket endpoints that are in this rsocket_group.
290 @par Threads
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(
300 /// Data to send
301 const void* msg,
302 /// Number of bytes to send
303 const size_t len,
304 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
305 const int flags = 0) noexcept {
306
307 // --------------------------------------------------------------------------
308 // Internal variables.
309 // --------------------------------------------------------------------------
310 std::vector<rsocket_group_rc> v1;
311 std::vector<rsocket_group_rc> v2;
312
313 // --------------------------------------------------------------------------
314 // Loop through all rsocket objects in the underlying std::set.
315 //
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) + "}"
321 + ", <std::string>"
322 + ", " + std::to_string(len)
323 + ", " + std::to_string(flags)
324 + ");");
325 try {
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});
329 }
330 } // -x- if r.lock() -x-
331 } // -x- foreach __r -x-
332
333 return std::pair(v1, v2);
334 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> __send -x-
335
336 /*======================================================================*//**
337 @brief
338 Send data that included a final EoL sequence to all rsocket endpoints that
339 are in this rsocket_group.
340 @par Threads
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(
350 /// Data to send
351 const void* msg,
352 /// Number of bytes to send
353 const size_t len,
354 /// MSG_DONTROUTE@n MSG_DONTWAIT@n MSG_EOR@n MSG_NOSIGNAL@n MSG_OOB
355 const int flags = 0) noexcept {
356
357 // --------------------------------------------------------------------------
358 // Internal variables.
359 // --------------------------------------------------------------------------
360 std::vector<rsocket_group_rc> v1;
361 std::vector<rsocket_group_rc> v2;
362
363 // --------------------------------------------------------------------------
364 // Loop through all rsocket objects in the underlying std::set.
365 //
366 // We don't need a mutex lock here because the __sendline method is
367 // threadsafe.
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) + "}"
372 + ", <std::string>"
373 + ", " + std::to_string(len)
374 + ", " + std::to_string(flags)
375 + ");");
376 try {
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});
380 }
381 } // -x- if r.lock() -x-
382 } // -x- foreach __r -x-
383
384 return std::pair(v1, v2);
385 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> __sendline -x-
386
387 /*======================================================================*//**
388 @brief
389 Send data that is the final EoL sequence to all rsocket endpoints that are in
390 this rsocket_group.
391 @par Threads
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 {
403
404 // --------------------------------------------------------------------------
405 // Internal variables.
406 // --------------------------------------------------------------------------
407 std::vector<rsocket_group_rc> v1;
408 std::vector<rsocket_group_rc> v2;
409
410 // --------------------------------------------------------------------------
411 // Loop through all rsocket objects in the underlying std::set.
412 //
413 // We don't need a mutex lock here because the __sendline method is
414 // threadsafe.
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)
420 + ");");
421 try {
422 v1.push_back({r.get(), r->__send_eol(flags), nullptr});
423 } catch (std::exception* e) {
424 v2.push_back({r.get(), 0, e});
425 }
426 } // -x- if r.lock() -x-
427 } // -x- foreach __r -x-
428
429 return std::pair(v1, v2);
430 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> __send_eol -x-
431
432 public:
433 /*======================================================================*//**
434 @brief
435 Send data in the form of a std::string to all rsocket endpoints that are in
436 this rsocket_group.
437 @par Threads
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(
447 /// Data to 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-
453
454 /*======================================================================*//**
455 @brief
456 Send data in the form of a std::vector<char> to all rsocket endpoints that
457 are in this rsocket_group.
458 @par Threads
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(
468 /// Data to 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-
474
475 /*======================================================================*//**
476 @brief
477 Send data in the form of a C-string to all rsocket endpoints that are in this
478 rsocket_group.
479 @par Threads
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
490 const char* msg,
491 /// Number of bytes to send
492 const size_t len,
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-
497
498 /*======================================================================*//**
499 @brief
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.
502 @par Threads
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
510 NULL character
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
515 const char* msg,
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-
520
521 /*======================================================================*//**
522 @brief
523 Send one byte of data to all rsocket endpoints that are in this
524 rsocket_group.
525 @par Threads
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(
535 /// Data to send
536 const char value,
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-
541
542 /*======================================================================*//**
543 @brief
544 Send the EoL sequence to all rsocket endpoints that are in this
545 rsocket_group.
546 @par Threads
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-
555
556 /*======================================================================*//**
557 @brief
558 Send one byte of data to all rsocket endpoints that are in this
559 rsocket_group.
560 @par Threads
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(
570 /// Data to send
571 const T value,
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-
576
577 /*======================================================================*//**
578 @brief
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.
581 @par Threads
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(
591 /// Data to send
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-
598
599 /*======================================================================*//**
600 @brief
601 Send one 16-bit integer of data in MSB (big endian) order to all rsocket
602 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_msb(const uint16_t, const int)
611 *///=========================================================================
612 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint16_msb(
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 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-
620
621 /*======================================================================*//**
622 @brief
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.
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_uint32_lsb(const uint32_t, const int)
633 *///=========================================================================
634 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint32_lsb(
635 /// Data to send
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-
642
643 /*======================================================================*//**
644 @brief
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.
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_msb(const uint32_t, const int)
655 *///=========================================================================
656 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint32_msb(
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 : 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-
664
665 /*======================================================================*//**
666 @brief
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.
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_uint64_lsb(const uint64_t, const int)
677 *///=========================================================================
678 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint64_lsb(
679 /// Data to send
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-
686
687 /*======================================================================*//**
688 @brief
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.
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_msb(const uint64_t, const int)
699 *///=========================================================================
700 std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> send_uint64_msb(
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)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-
708
709 /*======================================================================*//**
710 @brief
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
714 @par Threads
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(
725 /// Data to send
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-
731
732 /*======================================================================*//**
733 @brief
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.
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 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
748 const char* msg,
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-
753
754 /*======================================================================*//**
755 @brief
756 Shut down the underlying sockets in all rsocket objects that are in this
757 rsocket_group, partially or fully.
758
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) {
773
774 // --------------------------------------------------------------------------
775 // Internal variables.
776 // --------------------------------------------------------------------------
777 std::vector<rsocket_group_rc> v1;
778 std::vector<rsocket_group_rc> v2;
779
780 // --------------------------------------------------------------------------
781 // Loop through all rsocket objects in the underlying std::set.
782 //
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
787 try {
788 r->shutdown(how);
789 v1.push_back({r.get(), 0, nullptr});
790 } catch (std::exception* e) {
791 v2.push_back({r.get(), 0, e});
792 }
793 } // -x- if r.lock() -x-
794 } // -x- foreach __r -x-
795
796 return std::pair(v1, v2);
797 }; // -x- std::pair<std::vector<rsocket_group_rc>, std::vector<rsocket_group_rc>> shutdown -x-
798
799 /*======================================================================*//**
800 @brief
801 Find out how many rsocket entries are in this group.
802
803 @par Threads
804 This method is threadsafe.
805 @returns Number of rsocket objects in the underlying std::set
806 *///=========================================================================
807 size_t size() {
808 const std::lock_guard<std::mutex> lock(__mutex);
809 return __r.size();
810 }; // -x- size_t size -x-
811
812 }; // -x- class rsocket_group -x-
813
814}; // -x- namespace randolf -x-