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