4#ifndef _Stroika_Foundation_IO_Network_Socket_Private_h_
5#define _Stroika_Foundation_IO_Network_Socket_Private_h_ 1
7#include "Stroika/Foundation/StroikaPreComp.h"
14#if qStroika_Foundation_Common_Platform_POSIX
18#include <sys/socket.h>
20#elif qStroika_Foundation_Common_Platform_Windows
28#if qStroika_Foundation_Common_Platform_Linux
29#include <netinet/in.h>
30#include <netinet/tcp.h>
35#include "Stroika/Foundation/Execution/OperationNotSupportedException.h"
36#if qStroika_Foundation_Common_Platform_Windows
37#include "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
38#include "Stroika/Foundation/IO/Network/Platform/Windows/WinSock.h"
54 using namespace Stroika::Foundation::Memory;
55 using namespace Stroika::Foundation::IO;
60#if qStroika_Foundation_Common_Platform_POSIX
66#elif qStroika_Foundation_Common_Platform_Windows
71 void BreakWriteIntoParts_ (span<const T> data,
size_t maxSendAtATime,
const function<
size_t (span<const T>)>& writeFunc)
73#if USE_NOISY_TRACE_IN_THIS_MODULE_
76 ptrdiff_t amountToSend = data.size ();
77 ptrdiff_t amountRemainingToSend = amountToSend;
78 const T* remainingSendFrom = data.data ();
79 while (amountRemainingToSend > 0) {
80 size_t amountToSendThisIteration = min<size_t> (maxSendAtATime, amountRemainingToSend);
81 size_t amountSent = writeFunc (span{remainingSendFrom, amountToSendThisIteration});
82 Assert (amountSent <= amountToSendThisIteration);
83 Assert (
static_cast<size_t> (amountRemainingToSend) >= amountSent);
84 amountRemainingToSend -= amountSent;
85 remainingSendFrom += amountSent;
86#if USE_NOISY_TRACE_IN_THIS_MODULE_
87 if (amountSent < amountToSendThisIteration) {
89 L
"write broken into parts - amountSent=%lld out of amountToSendThisIteration=%lld, amountRemainingToSend=%lld",
90 static_cast<long long> (amountSent),
static_cast<long long> (amountToSendThisIteration),
91 static_cast<long long> (amountRemainingToSend));
97 template <
typename BASE_REP>
98 struct BackSocketImpl_ :
public BASE_REP {
106 if (fSD_ != kINVALID_NATIVE_HANDLE_) {
114 fSD_ = kINVALID_NATIVE_HANDLE_;
117 virtual void Shutdown (Socket::ShutdownTarget shutdownTarget)
override
120 if (fSD_ != kINVALID_NATIVE_HANDLE_) {
122 switch (shutdownTarget) {
123 case Socket::ShutdownTarget::eReads:
124#if qStroika_Foundation_Common_Platform_POSIX
125 ::shutdown (fSD_, SHUT_RD);
126#elif qStroika_Foundation_Common_Platform_Windows
127 ::shutdown (fSD_, SD_RECEIVE);
130 case Socket::ShutdownTarget::eWrites:
132#if qStroika_Foundation_Common_Platform_POSIX
133 ::shutdown (fSD_, SHUT_WR);
134#elif qStroika_Foundation_Common_Platform_Windows
135 ::shutdown (fSD_, SD_SEND);
138 case Socket::ShutdownTarget::eBoth:
139#if qStroika_Foundation_Common_Platform_POSIX
140 ::shutdown (fSD_, SHUT_RDWR);
141#elif qStroika_Foundation_Common_Platform_Windows
142 ::shutdown (fSD_, SD_BOTH);
150 virtual void Close ()
override
153 if (fSD_ != kINVALID_NATIVE_HANDLE_) {
154#if qStroika_Foundation_Common_Platform_POSIX
156#elif qStroika_Foundation_Common_Platform_Windows
157 ::closesocket (fSD_);
161 fSD_ = kINVALID_NATIVE_HANDLE_;
164 virtual optional<IO::Network::SocketAddress> GetLocalAddress ()
const override
167 struct sockaddr_storage radr;
168 socklen_t len =
sizeof (radr);
169 if (::getsockname (
static_cast<int> (fSD_), (
struct sockaddr*)&radr, &len) == 0) {
178#if defined(SO_DOMAIN)
179 return getsockopt<SocketAddress::FamilyType> (SOL_SOCKET, SO_DOMAIN);
180#elif defined(SO_PROTOCOL)
181 return getsockopt<SocketAddress::FamilyType> (SOL_SOCKET, SO_PROTOCOL);
182#elif qStroika_Foundation_Common_Platform_Windows
190 sockaddr_storage bcast;
191 bool isV6 = (WSAIoctl (this->GetNativeSocket (), SIO_GET_BROADCAST_ADDRESS, NULL, 0, &bcast,
sizeof (bcast), &dwBytesRet,
192 NULL, NULL) == SOCKET_ERROR);
194 Assert (::WSAGetLastError () == WSAENOPROTOOPT);
196 return isV6 ? SocketAddress::FamilyType::INET6 : SocketAddress::FamilyType::INET;
206 virtual void getsockopt (
int level,
int optname,
void* optval, socklen_t* optvallen)
const override
211#if qStroika_Foundation_Common_Platform_POSIX
213#elif qStroika_Foundation_Common_Platform_Windows
214 ThrowWSASystemErrorIfSOCKET_ERROR (::getsockopt (fSD_, level, optname,
reinterpret_cast<char*
> (optval), optvallen));
219 template <
typename RESULT_TYPE>
220 inline RESULT_TYPE getsockopt (
int level,
int optname)
const
224 socklen_t roptlen =
sizeof (r);
225 this->getsockopt (level, optname, &r, &roptlen);
228 virtual void setsockopt (
int level,
int optname,
const void* optval, socklen_t optvallen)
override
233#if qStroika_Foundation_Common_Platform_POSIX
235#elif qStroika_Foundation_Common_Platform_Windows
236 ThrowWSASystemErrorIfSOCKET_ERROR (::setsockopt (fSD_, level, optname,
reinterpret_cast<const char*
> (optval), optvallen));
241 template <
typename ARG_TYPE>
242 inline void setsockopt (
int level,
int optname, ARG_TYPE arg)
244 socklen_t optvallen =
sizeof (arg);
245 this->setsockopt (level, optname, &arg, optvallen);
#define AssertNotImplemented()
#define RequireNotReached()
#define RequireNotNull(p)
#define Stroika_Foundation_Debug_OptionalizeTraceArgs(...)
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)
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
INT_TYPE ThrowPOSIXErrNoIfNegative(INT_TYPE returnCode)