Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
ConnectionOrientedStreamSocket.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Foundation/StroikaPreComp.h"
5
6#if qStroika_Foundation_Common_Platform_POSIX
7#include <fcntl.h>
8#include <netinet/in.h>
9#include <netinet/tcp.h>
10#include <sys/socket.h>
11#include <sys/types.h>
12#include <unistd.h>
13#endif
14
18#include "Stroika/Foundation/IO/Network/ConnectionOrientedStreamSocket.h"
19#include "Stroika/Foundation/IO/Network/Socket-Private_.h"
21
22// Comment this in to turn on aggressive noisy DbgTrace in this module
23//#define USE_NOISY_TRACE_IN_THIS_MODULE_ 1
24
25using std::byte;
26
27using namespace Stroika::Foundation::IO::Network::PRIVATE_;
28
29using namespace ConnectionOrientedStreamSocket;
30
32
33namespace {
34 struct Rep_ : BackSocketImpl_<ConnectionOrientedStreamSocket::_IRep> {
35 using inherited = BackSocketImpl_<ConnectionOrientedStreamSocket::_IRep>;
37 : inherited{sd}
38 {
39#if USE_NOISY_TRACE_IN_THIS_MODULE_
40 DbgTrace ("Constructed BackSocketImpl_<ConnectionOrientedStreamSocket>::Rep_ with sd={:x}"_f, (int)sd);
41#endif
42 }
43 Rep_ () = delete;
44 Rep_ (const Rep_&) = delete;
45 ~Rep_ ()
46 {
47 // need DTOR cuz one in base class wont call this override of Close
48 if (fSD_ != kINVALID_NATIVE_HANDLE_) {
49 Close ();
50 }
51 }
52 virtual void Close () override
53 {
54 AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized};
55 if (fSD_ != kINVALID_NATIVE_HANDLE_ and fAutomaticTCPDisconnectOnClose_) {
56 Shutdown (Socket::ShutdownTarget::eWrites);
57 Time::TimePointSeconds timeOutAt = Time::GetTickCount () + *fAutomaticTCPDisconnectOnClose_;
58 Execution::WaitForIOReady ioReady{fSD_};
59 try {
60 again:
61 (void)ioReady.WaitUntil (timeOutAt);
62 char data[1024];
63#if qStroika_Foundation_Common_Platform_POSIX
64 int nb = ::read (fSD_, data, NEltsOf (data));
65#elif qStroika_Foundation_Common_Platform_Windows
66 int flags = 0;
67 int nb = ::recv (fSD_, data, (int)NEltsOf (data), flags);
68#endif
69 if (nb > 0) {
70 DbgTrace ("Warning: {} unread bytes to be read on socket when it was closed."_f,
71 nb); // SHOULD READ ZERO AFTER SHUTDOWN to indicate client other side of connection handled the close
72 goto again;
73 }
74 }
75 catch (...) {
76#if USE_NOISY_TRACE_IN_THIS_MODULE_
77 DbgTrace (L"timeout closing down socket - not serious - just means client didn't send close ACK quickly enough");
78#endif
79 }
80 }
81 inherited::Close ();
82 }
83 nonvirtual void Connect_Sync_ (const SocketAddress& sockAddr) const
84 {
85 AssertExternallySynchronizedMutex::ReadContext declareContext{this->fThisAssertExternallySynchronized};
86 sockaddr_storage useSockAddr = sockAddr.As<sockaddr_storage> ();
87#if qStroika_Foundation_Common_Platform_POSIX
88 Handle_ErrNoResultInterruption ([&] () -> int { return ::connect (fSD_, (sockaddr*)&useSockAddr, sockAddr.GetRequiredSize ()); });
89#elif qStroika_Foundation_Common_Platform_Windows
90 ThrowWSASystemErrorIfSOCKET_ERROR (::connect (fSD_, (sockaddr*)&useSockAddr, static_cast<int> (sockAddr.GetRequiredSize ())));
91#else
93#endif
94 }
95 nonvirtual void Connect_AsyncWTimeout_ (const SocketAddress& sockAddr, const Time::Duration& timeout) const
96 {
97 AssertExternallySynchronizedMutex::ReadContext declareContext{this->fThisAssertExternallySynchronized};
98 sockaddr_storage useSockAddr = sockAddr.As<sockaddr_storage> ();
99#if qStroika_Foundation_Common_Platform_POSIX
100 // http://developerweb.net/viewtopic.php?id=3196.
101 // and see https://stackoverflow.com/questions/4181784/how-to-set-socket-timeout-in-c-when-making-multiple-connections/4182564#4182564 for why not using SO_RCVTIMEO/SO_SNDTIMEO
102 long savedFlags{};
103 ThrowPOSIXErrNoIfNegative (savedFlags = ::fcntl (fSD_, F_GETFL, nullptr));
104 ThrowPOSIXErrNoIfNegative (::fcntl (fSD_, F_SETFL, savedFlags | O_NONBLOCK)); // non-blocking mode for select
105 [[maybe_unused]] auto&& cleanup = Finally ([this, savedFlags] () noexcept {
106 // Set to blocking mode again...
107 if (::fcntl (fSD_, F_SETFL, savedFlags) < 0) {
108 AssertNotReached (); // cannot throw here
109 }
110 });
111 while (::connect (fSD_, (sockaddr*)&useSockAddr, sockAddr.GetRequiredSize ()) < 0) {
112 switch (errno) {
113 case EINTR:
114 break; // ignore - try again
115 case EINPROGRESS: {
116 fd_set myset;
117 FD_ZERO (&myset);
118 FD_SET (fSD_, &myset);
119 timeval time_out = timeout.As<timeval> ();
120 Handle_ErrNoResultInterruption ([&] () -> int {
121 auto r = ::select (fSD_ + 1, NULL, &myset, nullptr, &time_out);
122 if (r == 0) {
123 // https://man7.org/linux/man-pages/man2/select.2.html - "The return value may be zero if the timeout expired before any file descriptors became ready"
125 }
126 return r;
127 });
128 // Check the errno value returned...
129 if (auto err = getsockopt<int> (SOL_SOCKET, SO_ERROR)) {
130 Execution::ThrowSystemErrNo (err);
131 }
132 return; // else must have succeeded
133 } break;
134 default: {
135 Execution::ThrowSystemErrNo ();
136 } break;
137 }
138 }
139#elif qStroika_Foundation_Common_Platform_Windows
140 // https://stackoverflow.com/questions/46045434/winsock-c-connect-timeout
141 {
142 u_long block = 1;
143 if (::ioctlsocket (fSD_, FIONBIO, &block) == SOCKET_ERROR) {
144 Execution::ThrowSystemErrNo (::WSAGetLastError ());
145 }
146 }
147 [[maybe_unused]] auto&& cleanup = Finally ([this] () noexcept {
148 u_long block = 0; // should have saved old value, but not clear how to read?
149 if (::ioctlsocket (fSD_, FIONBIO, &block) == SOCKET_ERROR) {
150 //Execution::ThrowSystemErrNo (::WSAGetLastError ());
151 Assert (false); //FAILURE SETTING BACK TO NOT BLOCKING - SERIOUS
152 }
153 });
154 if (::connect (fSD_, (sockaddr*)&useSockAddr, static_cast<int> (sockAddr.GetRequiredSize ())) == SOCKET_ERROR) {
155 if (::WSAGetLastError () != WSAEWOULDBLOCK) {
156 Execution::ThrowSystemErrNo (::WSAGetLastError ()); // connection failed
157 }
158 // connection pending
159 fd_set setW;
160 FD_ZERO (&setW);
161 FD_SET (fSD_, &setW);
162 fd_set setE;
163 FD_ZERO (&setE);
164 FD_SET (fSD_, &setE);
165 timeval time_out = timeout.As<timeval> ();
166 int ret = ::select (0, NULL, &setW, &setE, &time_out);
167 if (ret <= 0) {
168 // select() failed or connection timed out
169 if (ret == 0) {
170 WSASetLastError (WSAETIMEDOUT);
171 }
172 Execution::ThrowSystemErrNo (::WSAGetLastError ()); // connection failed
173 }
174 // Check the errno value returned...
175 if (auto err = getsockopt<int> (SOL_SOCKET, SO_ERROR)) {
176 Execution::ThrowSystemErrNo (err);
177 }
178 // else if got here >0 so succeeded with connection
179 }
180#else
182#endif
183 }
184 virtual void Connect (const SocketAddress& sockAddr, const optional<Time::Duration>& timeout) const override
185 {
186 Debug::TraceContextBumper ctx{"ConnectionOrientedStreamSocket_IMPL_::Connect", "sockAddr={}, timeout={}"_f, sockAddr, timeout};
187 if (timeout) {
188 Connect_AsyncWTimeout_ (sockAddr, *timeout);
189 }
190 else {
191 Connect_Sync_ (sockAddr);
192 }
193 }
194 virtual span<byte> Read (span<byte> into) const override
195 {
196 AssertExternallySynchronizedMutex::ReadContext declareContext{this->fThisAssertExternallySynchronized};
197
198#if qStroika_Foundation_Debug_AssertionsChecked
199 Assert (fCurrentPendingReadsCount++ == 0);
200 [[maybe_unused]] auto&& cleanup = Finally ([this] () noexcept { Assert (--fCurrentPendingReadsCount == 0); });
201#endif
202
203#if qStroika_Foundation_Common_Platform_POSIX
204 return into.subspan (
205 0, Handle_ErrNoResultInterruption ([this, &into] () -> int { return ::read (fSD_, into.data (), into.size ()); }));
206#elif qStroika_Foundation_Common_Platform_Windows
207 int flags = 0;
208 int nBytesToRead = static_cast<int> (min<size_t> (into.size (), numeric_limits<int>::max ()));
209 return into.subspan (0, static_cast<size_t> (ThrowWSASystemErrorIfSOCKET_ERROR (
210 ::recv (fSD_, reinterpret_cast<char*> (into.data ()), nBytesToRead, flags))));
211#else
213#endif
214 }
215 virtual optional<span<byte>> ReadNonBlocking (span<byte> into) const override
216 {
217 AssertExternallySynchronizedMutex::ReadContext declareContext{this->fThisAssertExternallySynchronized};
218 if (AvailableToRead ()) {
219 return Read (into);
220 }
221 return nullopt;
222 }
223 virtual optional<size_t> AvailableToRead () const override
224 {
225 AssertExternallySynchronizedMutex::ReadContext declareContext{this->fThisAssertExternallySynchronized};
226#if qStroika_Foundation_Debug_AssertionsChecked
227 Assert (fCurrentPendingReadsCount++ == 0);
228 [[maybe_unused]] auto&& cleanup = Finally ([this] () noexcept { Assert (--fCurrentPendingReadsCount == 0); });
229#endif
230#if qStroika_Foundation_Common_Platform_POSIX or qStroika_Foundation_Common_Platform_Windows
231 {
232 fd_set input;
233 FD_ZERO (&input);
234 FD_SET (fSD_, &input);
235 struct timeval timeout{};
236 if (::select (static_cast<int> (fSD_) + 1, &input, NULL, NULL, &timeout) == 1) {
237 // don't know how much, but doesn't matter, since read allows returning just one byte if thats all thats available
238 // But MUST check if is EOF or real data available
239 char buf[1024];
240#if qStroika_Foundation_Common_Platform_POSIX
241 int tmp = Handle_ErrNoResultInterruption ([&] () -> int { return ::recv (fSD_, buf, NEltsOf (buf), MSG_PEEK); });
242#elif qStroika_Foundation_Common_Platform_Windows
243 int tmp = ThrowWSASystemErrorIfSOCKET_ERROR (::recv (fSD_, buf, static_cast<int> (NEltsOf (buf)), MSG_PEEK));
244#else
246#endif
247 return tmp;
248 }
249 else {
250 return {};
251 }
252 }
253#else
255 return {};
256#endif
257 }
258 virtual void Write (span<const byte> data) const override
259 {
260 AssertExternallySynchronizedMutex::ReadContext declareContext{this->fThisAssertExternallySynchronized};
261#if USE_NOISY_TRACE_IN_THIS_MODULE_
263 Stroika_Foundation_Debug_OptionalizeTraceArgs ("IO::Network::Socket...rep...::Write", "lwn={}"_f, data.size ())};
264#endif
265#if qStroika_Foundation_Common_Platform_POSIX
266 /*
267 * https://linux.die.net/man/2/write says "writes up to count bytes". So handle case where we get partial writes.
268 * Actually, for most of the cases called out, we cannot really continue anyhow, so this maybe pointless, but the
269 * docs aren't fully clear, so play it safe --LGP 2017-04-13
270 */
271 BreakWriteIntoParts_<byte> (data, numeric_limits<int>::max (), [this] (span<const byte> data) -> size_t {
272 Assert (data.size () < numeric_limits<int>::max ());
273 ssize_t n =
274 Handle_ErrNoResultInterruption ([this, &data] () -> ssize_t { return ::write (fSD_, data.data (), data.size ()); });
276 Assert (0 <= n and n <= data.size ());
277 return static_cast<size_t> (n);
278 });
279#elif qStroika_Foundation_Common_Platform_Windows
280 /*
281 * Note sure what the best way is here, but with WinSock, you cannot use write() directly. Sockets are not
282 * file descriptors in windows implementation.
283 * WONT WORK:
284 * int n = ::_write (fSD_, start, end - start);
285 */
286 size_t maxSendAtATime = getsockopt<unsigned int> (SOL_SOCKET, SO_MAX_MSG_SIZE);
287 BreakWriteIntoParts_<byte> (data, maxSendAtATime, [this, maxSendAtATime] (span<const byte> data) -> size_t {
288 Require (data.size () <= maxSendAtATime);
289 Assert (data.size () < static_cast<size_t> (numeric_limits<int>::max ()));
290 int len = static_cast<int> (data.size ());
291 int flags = 0;
292 int n = ThrowWSASystemErrorIfSOCKET_ERROR (::send (fSD_, reinterpret_cast<const char*> (data.data ()), len, flags));
293 Assert (0 <= n and static_cast<size_t> (n) <= data.size ());
294 return static_cast<size_t> (n);
295 });
296#else
298#endif
299 }
300 virtual optional<IO::Network::SocketAddress> GetPeerAddress () const override
301 {
302 AssertExternallySynchronizedMutex::ReadContext declareContext{this->fThisAssertExternallySynchronized};
303 struct sockaddr_storage radr;
304 socklen_t len = sizeof (radr);
305 if (::getpeername (static_cast<int> (fSD_), (struct sockaddr*)&radr, &len) == 0) {
307 return sa;
308 }
309 return nullopt;
310 }
311 virtual optional<Time::DurationSeconds> GetAutomaticTCPDisconnectOnClose () const override
312 {
313 AssertExternallySynchronizedMutex::ReadContext declareContext{this->fThisAssertExternallySynchronized};
314 return fAutomaticTCPDisconnectOnClose_;
315 }
316 virtual void SetAutomaticTCPDisconnectOnClose (const optional<Time::DurationSeconds>& waitFor) override
317 {
318 AssertExternallySynchronizedMutex::WriteContext declareContext{this->fThisAssertExternallySynchronized};
319 fAutomaticTCPDisconnectOnClose_ = waitFor;
320 }
321 virtual KeepAliveOptions GetKeepAlives () const override
322 {
323 AssertExternallySynchronizedMutex::ReadContext declareContext{this->fThisAssertExternallySynchronized};
324 KeepAliveOptions result;
325 result.fEnabled = !!getsockopt<int> (SOL_SOCKET, SO_KEEPALIVE);
326#if qStroika_Foundation_Common_Platform_Linux
327 // Only available if linux >= 2.4
328 result.fMaxProbesSentBeforeDrop = getsockopt<int> (SOL_TCP, TCP_KEEPCNT);
329 result.fTimeIdleBeforeSendingKeepalives = Time::DurationSeconds{getsockopt<int> (SOL_TCP, TCP_KEEPIDLE)};
330 result.fTimeBetweenIndividualKeepaliveProbes = Time::DurationSeconds{getsockopt<int> (SOL_TCP, TCP_KEEPINTVL)};
331#elif qStroika_Foundation_Common_Platform_Windows
332// WSAIoctl (..., SIO_KEEPALIVE_VALS) can be used to set some of these values, but I can find no way
333// to fetch them --LGP 2017-02-27
334#endif
335 return result;
336 }
337 virtual void SetKeepAlives (const KeepAliveOptions& keepAliveOptions) override
338 {
339 AssertExternallySynchronizedMutex::WriteContext declareContext{this->fThisAssertExternallySynchronized};
340 setsockopt<int> (SOL_SOCKET, SO_KEEPALIVE, keepAliveOptions.fEnabled);
341#if qStroika_Foundation_Common_Platform_Linux
342 // Only available if linux >= 2.4
343 if (keepAliveOptions.fMaxProbesSentBeforeDrop) {
344 setsockopt<int> (SOL_TCP, TCP_KEEPCNT, *keepAliveOptions.fMaxProbesSentBeforeDrop);
345 }
346 if (keepAliveOptions.fTimeIdleBeforeSendingKeepalives) {
347 setsockopt<int> (SOL_TCP, TCP_KEEPIDLE, static_cast<int> (keepAliveOptions.fTimeIdleBeforeSendingKeepalives->count ()));
348 }
349 if (keepAliveOptions.fTimeBetweenIndividualKeepaliveProbes) {
350 setsockopt<int> (SOL_TCP, TCP_KEEPINTVL, static_cast<int> (keepAliveOptions.fTimeBetweenIndividualKeepaliveProbes->count ()));
351 }
352#elif qStroika_Foundation_Common_Platform_Windows
353 // windows only allows setting these two, and both at the same time
354 if (keepAliveOptions.fEnabled and
355 (keepAliveOptions.fTimeIdleBeforeSendingKeepalives or keepAliveOptions.fTimeBetweenIndividualKeepaliveProbes)) {
356 tcp_keepalive alive{keepAliveOptions.fEnabled};
357 // from https://msdn.microsoft.com/en-us/library/windows/desktop/dd877220(v=vs.85).aspx - "The default settings when a TCP socket is initialized sets the keep-alive timeout to 2 hours and the keep-alive interval to 1 second"
358 alive.keepalivetime = Math::Round<ULONG> (keepAliveOptions.fTimeIdleBeforeSendingKeepalives.value_or (2 * 60 * 60s).count () * 1000.0);
359 alive.keepaliveinterval = Math::Round<ULONG> (keepAliveOptions.fTimeBetweenIndividualKeepaliveProbes.value_or (1s).count () * 1000.0);
360 DWORD dwBytesRet{};
361 if (::WSAIoctl (fSD_, SIO_KEEPALIVE_VALS, &alive, sizeof (alive), NULL, 0, &dwBytesRet, NULL, NULL) == SOCKET_ERROR) {
362 Execution::ThrowSystemErrNo (::WSAGetLastError ());
363 }
364 }
365#endif
366 }
367 virtual bool GetTCPNoDelay () const override
368 {
369 AssertExternallySynchronizedMutex::ReadContext declareContext{this->fThisAssertExternallySynchronized};
370 return static_cast<bool> (getsockopt<int> (IPPROTO_TCP, TCP_NODELAY));
371 }
372 virtual void SetTCPNoDelay (bool noDelay) override
373 {
374 AssertExternallySynchronizedMutex::WriteContext declareContext{this->fThisAssertExternallySynchronized};
375 setsockopt<int> (IPPROTO_TCP, TCP_NODELAY, noDelay);
376 }
377 optional<Time::DurationSeconds> fAutomaticTCPDisconnectOnClose_;
378#if qStroika_Foundation_Debug_AssertionsChecked
379 mutable atomic<int> fCurrentPendingReadsCount{};
380#endif
381 };
382}
383
384/*
385 ********************************************************************************
386 ********** Network::ConnectionOrientedStreamSocket::KeepAliveOptions ***********
387 ********************************************************************************
388 */
389Characters::String Network::ConnectionOrientedStreamSocket::KeepAliveOptions::ToString () const
390{
392 sb << "{"sv;
393 sb << "Enabled: "sv << fEnabled;
394#if qStroika_Foundation_Common_Platform_Linux or qStroika_Foundation_Common_Platform_Windows
395 if (fMaxProbesSentBeforeDrop) {
396 sb << ", Max-Probes-Sent-Before-Drop: "sv << fMaxProbesSentBeforeDrop;
397 }
398 if (fTimeIdleBeforeSendingKeepalives) {
399 sb << ", Time-Idle-Before-Sending-Keepalives: "sv << fTimeIdleBeforeSendingKeepalives;
400 }
401 if (fTimeBetweenIndividualKeepaliveProbes) {
402 sb << ", Time-Between-Individual-Keepalive-Probes: "sv << fTimeBetweenIndividualKeepaliveProbes;
403 }
404#endif
405 sb << "}"sv;
406 return sb;
407}
408
409/*
410 ********************************************************************************
411 ******************** ConnectionOrientedStreamSocket ****************************
412 ********************************************************************************
413 */
414ConnectionOrientedStreamSocket::Ptr ConnectionOrientedStreamSocket::New (SocketAddress::FamilyType family, Type socketKind, const optional<IPPROTO>& protocol)
415{
416 return Ptr{make_shared<Rep_> (_Protected::mkLowLevelSocket_ (family, socketKind, protocol))};
417}
418
419ConnectionOrientedStreamSocket::Ptr ConnectionOrientedStreamSocket::Attach (PlatformNativeHandle sd)
420{
421 return Ptr{make_shared<Rep_> (sd)};
422}
423
424#include "ConnectionOrientedMasterSocket.h" //tmphack for kLowLevelSocketPairWorks_==false
425auto ConnectionOrientedStreamSocket::NewPair (SocketAddress::FamilyType family, Type socketKind, const optional<IPPROTO>& protocol) -> tuple<Ptr, Ptr>
426{
427 constexpr bool kLowLevelSocketPairWorks_{true}; // for now only works on windows
428 if constexpr (kLowLevelSocketPairWorks_) {
429 auto sp = _Protected::mkLowLevelSocketPair_ (family, socketKind, protocol);
430 return make_tuple (Attach (get<0> (sp)), Attach (get<1> (sp)));
431 }
432 else {
433 // Create a Listening master socket, bind it, and get it listening
434 // Just needed temporarily to create the socketpair, then it can be closed when it goes out of scope
435 auto connectionOrientedMaster = ConnectionOrientedMasterSocket::New (family, socketKind, protocol);
436 connectionOrientedMaster.Bind (SocketAddress{LocalHost (family)});
437 connectionOrientedMaster.Listen (1);
438
439 // now make a NEW socket, with the bound address and connect;
440 auto one = ConnectionOrientedStreamSocket::NewConnection (*connectionOrientedMaster.GetLocalAddress ());
441 auto two = connectionOrientedMaster.Accept ();
442 return make_tuple (one, two);
443 }
444}
445
446/*
447 ********************************************************************************
448 ******************** ConnectionOrientedStreamSocket::Ptr ***********************
449 ********************************************************************************
450 */
452{
453 linger lr = getsockopt<linger> (SOL_SOCKET, SO_LINGER);
454 return lr.l_onoff ? lr.l_linger : optional<int>{};
455}
456
457void ConnectionOrientedStreamSocket::Ptr::SetLinger (const optional<int>& linger) const
458{
459 ::linger so_linger{};
460 if (linger) {
461 so_linger.l_onoff = true;
462 so_linger.l_linger = static_cast<u_short> (*linger);
463 }
464 setsockopt<::linger> (SOL_SOCKET, SO_LINGER, so_linger);
465}
#define AssertNotImplemented()
Definition Assertions.h:401
#define AssertNotReached()
Definition Assertions.h:355
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
Definition Realtime.h:82
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Definition Realtime.h:57
#define DbgTrace
Definition Trace.h:309
#define Stroika_Foundation_Debug_OptionalizeTraceArgs(...)
Definition Trace.h:270
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
shared_lock< const AssertExternallySynchronizedMutex > ReadContext
Instantiate AssertExternallySynchronizedMutex::ReadContext to designate an area of code where protect...
unique_lock< AssertExternallySynchronizedMutex > WriteContext
Instantiate AssertExternallySynchronizedMutex::WriteContext to designate an area of code where protec...
FamilyType
Socket address family - also sometimes referred to as domain (argument to ::socket calls it domain)
Duration is a chrono::duration<double> (=.
Definition Duration.h:96
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
Definition Throw.inl:43
auto Handle_ErrNoResultInterruption(CALL call) -> decltype(call())
Handle UNIX EINTR system call behavior - fairly transparently - just effectively removes them from th...
auto Finally(FUNCTION &&f) -> Private_::FinallySentry< FUNCTION >
Definition Finally.inl:31
INT_TYPE ThrowPOSIXErrNoIfNegative(INT_TYPE returnCode)
Ptr New(SocketAddress::FamilyType family, Type socketKind, const optional< IPPROTO > &protocol={})
constexpr InternetAddress LocalHost(SocketAddress::FamilyType fm)
return V4::kLocalhost or V6::kLocalhost depending on argument address family