4#include "Stroika/Foundation/StroikaPreComp.h"
8#include "Stroika/Foundation/Execution/Activity.h"
11#include "Socket-Private_.h"
21using namespace Stroika::Foundation::Memory;
22using namespace Stroika::Foundation::IO;
25using namespace Stroika::Foundation::IO::Network::PRIVATE_;
41 constexpr bool kUseDualStackSockets_ =
false;
50 const optional<IPPROTO>& protocol)
52#if qStroika_Foundation_Common_Platform_Windows
53 IO::Network::Platform::Windows::WinSock::AssureStarted ();
56#if qStroika_Foundation_Common_Platform_POSIX
58 return socket (
static_cast<int> (family),
static_cast<int> (socketKind),
static_cast<int> (NullCoalesce (protocol)));
60#elif qStroika_Foundation_Common_Platform_Windows
62 ThrowWSASystemErrorIfSOCKET_ERROR (
63 sfd = ::socket (static_cast<
int> (family), static_cast<
int> (socketKind), static_cast<
int> (NullCoalesce (protocol))));
64 DISABLE_COMPILER_MSC_WARNING_END (28193)
68 if (family == SocketAddress::FamilyType::INET6) {
69 int useIPV6Only = not kUseDualStackSockets_;
70#if qStroika_Foundation_Common_Platform_Linux
72 constexpr bool kOSDefaultIPV6Only_{
false};
73 bool mustSet = useIPV6Only != kOSDefaultIPV6Only_;
76 constexpr bool kOSDefaultIPV6Only_{
true};
77 bool mustSet = useIPV6Only != kOSDefaultIPV6Only_;
82 if (::setsockopt (sfd, IPPROTO_IPV6, IPV6_V6ONLY,
reinterpret_cast<const char*
> (&useIPV6Only),
sizeof (useIPV6Only)) < 0) {
93 -> tuple<PlatformNativeHandle, PlatformNativeHandle>
96 PlatformNativeHandle masterSocket = Socket::_Protected::mkLowLevelSocket_ (family, socketKind, protocol);
97#if qStroika_Foundation_Common_Platform_POSIX
98 [[maybe_unused]]
auto&& cleanup =
Execution::Finally ([&] ()
noexcept { ::close (masterSocket); });
99#elif qStroika_Foundation_Common_Platform_Windows
100 [[maybe_unused]]
auto&& cleanup =
Execution::Finally ([&] ()
noexcept { ::closesocket (masterSocket); });
106 sockaddr_storage localhost_ss = localhost.
As<sockaddr_storage> ();
110 Verify (::setsockopt (masterSocket, SOL_SOCKET, SO_REUSEADDR,
reinterpret_cast<const char*
> (&one),
sizeof (one)) == 0);
112#if qStroika_Foundation_Common_Platform_POSIX
114 return ::bind (masterSocket, (sockaddr*)&localhost_ss,
static_cast<int> (localhost.GetRequiredSize ()));
116#elif qStroika_Foundation_Common_Platform_Windows
117 ThrowWSASystemErrorIfSOCKET_ERROR (::bind (masterSocket, (sockaddr*)&localhost_ss,
static_cast<int> (localhost.GetRequiredSize ())));
121#if qStroika_Foundation_Common_Platform_POSIX
123#elif qStroika_Foundation_Common_Platform_Windows
124 ThrowWSASystemErrorIfSOCKET_ERROR (::listen (masterSocket, 1));
129 sockaddr_storage masterSocketLocalAddress_ss;
131 socklen_t len =
sizeof (masterSocketLocalAddress_ss);
132 Verify (::getsockname (
static_cast<int> (masterSocket), (sockaddr*)&masterSocketLocalAddress_ss, &len) == 0);
133 masterSocketLocalAddress = masterSocketLocalAddress_ss;
135 PlatformNativeHandle endOne = Socket::_Protected::mkLowLevelSocket_ (family, socketKind, protocol);
136 bool succeeded =
false;
139#if qStroika_Foundation_Common_Platform_POSIX
141#elif qStroika_Foundation_Common_Platform_Windows
142 ::closesocket (endOne);
146#if qStroika_Foundation_Common_Platform_POSIX
148 return ::connect (endOne, (sockaddr*)&masterSocketLocalAddress_ss,
static_cast<int> (masterSocketLocalAddress.
GetRequiredSize ()));
150#elif qStroika_Foundation_Common_Platform_Windows
151 ThrowWSASystemErrorIfSOCKET_ERROR (
152 ::connect (endOne, (sockaddr*)&masterSocketLocalAddress_ss,
static_cast<int> (masterSocketLocalAddress.
GetRequiredSize ())));
156 sockaddr_storage peer{};
157 socklen_t sz =
sizeof (peer);
158#if qStroika_Foundation_Common_Platform_POSIX
161#elif qStroika_Foundation_Common_Platform_Windows
162 PlatformNativeHandle endTwo = ThrowWSASystemErrorIfSOCKET_ERROR (::accept (masterSocket,
reinterpret_cast<sockaddr*
> (&peer), &sz));
165 return make_tuple (endOne, endTwo);
170 -> tuple<PlatformNativeHandle, PlatformNativeHandle>
172#if qStroika_Foundation_Common_Platform_POSIX
175 auto r = ::socketpair (
static_cast<int> (family),
static_cast<int> (socketKind),
static_cast<int> (NullCoalesce (protocol)), sfd);
176 Assert (r == 0 or r == -1);
178 if (errno == EOPNOTSUPP) {
179 return mkLowLevelSocketPair_BackCompat_ (family, socketKind, protocol);
181 Assert (errno != EINTR);
184 return make_tuple (sfd[0], sfd[1]);
185#elif qStroika_Foundation_Common_Platform_Windows
186 return mkLowLevelSocketPair_BackCompat_ (family, socketKind, protocol);
199 if (fRep_ !=
nullptr) {
200 h = fRep_->Detach ();
209 return getsockopt<Type> (SOL_SOCKET, SO_TYPE);
214 Debug::TraceContextBumper ctx{
"IO::Network::Socket::Bind",
"sockAddr={} bindFlags.fReUseAddr={}"_f, sockAddr, bindFlags.fSO_REUSEADDR};
218 auto bindingActivity =
226 setsockopt<int> (SOL_SOCKET, SO_REUSEADDR, bindFlags.fSO_REUSEADDR ? 1 : 0);
228 sockaddr_storage useSockAddr = sockAddr.
As<sockaddr_storage> ();
231#if qStroika_Foundation_Common_Platform_Windows
232 ThrowWSASystemErrorIfSOCKET_ERROR (::bind (sfd, (sockaddr*)&useSockAddr,
static_cast<int> (sockAddr.
GetRequiredSize ())));
235 [sfd, &useSockAddr, &sockAddr] () ->
int { return ::bind (sfd, (sockaddr*)&useSockAddr, sockAddr.
GetRequiredSize ()); });
239 if (e.code () == errc::permission_denied) {
246 catch (
const system_error& e) {
247 if (e.code () == errc::permission_denied) {
259 if (fRep_ !=
nullptr) {
260 return fRep_->GetNativeSocket () != kINVALID_NATIVE_HANDLE_;
269 if (fRep_ ==
nullptr) {
274 sb <<
"Native-Socket: "sv
275 << ((fRep_->GetNativeSocket () == kINVALID_NATIVE_HANDLE_) ?
"CLOSED"sv :
Characters::ToString (fRep_->GetNativeSocket ()));
276 if (
auto ola = GetLocalAddress ()) {
277 sb <<
", Local-Address: "sv << *ola;
#define AssertNotImplemented()
#define RequireNotNull(p)
#define AssertNotReached()
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,...
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...
nonvirtual Characters::String GetBasicErrorMessage() const
nonvirtual PlatformNativeHandle Detach()
nonvirtual void Bind(const SocketAddress &sockAddr, BindFlags bindFlags=BindFlags{})
nonvirtual bool IsOpen() const
nonvirtual String ToString() const
nonvirtual Type GetType() const
nonvirtual size_t GetRequiredSize() const
FamilyType
Socket address family - also sometimes referred to as domain (argument to ::socket calls it domain)
String ToString(T &&t, ARGS... args)
Return a debug-friendly, display version of the argument: not guaranteed parsable or usable except fo...
DISABLE_COMPILER_MSC_WARNING_START(4996)
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
void ThrowPOSIXErrNo(errno_t errNo=errno)
treats errNo as a POSIX errno value, and throws a SystemError (subclass of @std::system_error) except...
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 >
constexpr InternetAddress LocalHost(SocketAddress::FamilyType fm)
return V4::kLocalhost or V6::kLocalhost depending on argument address family