diff --git a/CMakeLists.txt b/CMakeLists.txt index a27d17f..90899a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,11 +158,11 @@ function(set_target_common_gns_properties TGT) endif() if(CMAKE_SYSTEM_NAME MATCHES Linux) - target_compile_definitions(${TGT} PUBLIC POSIX LINUX) + target_compile_definitions(${TGT} PUBLIC LINUX) elseif(CMAKE_SYSTEM_NAME MATCHES Darwin) - target_compile_definitions(${TGT} PUBLIC POSIX OSX) + target_compile_definitions(${TGT} PUBLIC OSX) elseif(CMAKE_SYSTEM_NAME MATCHES FreeBSD) - target_compile_definitions(${TGT} PUBLIC POSIX FREEBSD) + target_compile_definitions(${TGT} PUBLIC FREEBSD) elseif(CMAKE_SYSTEM_NAME MATCHES Windows) target_compile_definitions(${TGT} PUBLIC _WINDOWS) if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") diff --git a/examples/example_chat.cpp b/examples/example_chat.cpp index a466905..c6e8773 100644 --- a/examples/example_chat.cpp +++ b/examples/example_chat.cpp @@ -22,7 +22,7 @@ #include #endif -#ifdef WIN32 +#ifdef _WIN32 #include // Ug, for NukeProcess -- see below #else #include @@ -43,7 +43,7 @@ SteamNetworkingMicroseconds g_logTimeZero; // down the thread that is reading from stdin. static void NukeProcess( int rc ) { - #ifdef WIN32 + #ifdef _WIN32 ExitProcess( rc ); #else (void)rc; // Unused formal parameter diff --git a/examples/trivial_signaling_client.cpp b/examples/trivial_signaling_client.cpp index a40b331..06959d9 100644 --- a/examples/trivial_signaling_client.cpp +++ b/examples/trivial_signaling_client.cpp @@ -14,7 +14,7 @@ #include #include -#ifdef POSIX +#ifdef VALVE_POSIX #include #include #include diff --git a/include/steam/steamtypes.h b/include/steam/steamtypes.h index 7b60434..85847f0 100644 --- a/include/steam/steamtypes.h +++ b/include/steam/steamtypes.h @@ -17,11 +17,13 @@ typedef unsigned char uint8; #endif -#if defined( __GNUC__ ) && !defined(_WIN32) && !defined(POSIX) +#if ( defined(POSIX) || defined(_POSIX_VERSION) || ( defined( __GNUC__ ) && !defined(_WIN32) ) ) && !defined(VALVE_POSIX) + #define VALVE_POSIX 1 +#endif +#ifdef __GNUC__ #if __GNUC__ < 4 #error "Steamworks requires GCC 4.X (4.2 or 4.4 have been tested)" #endif - #define POSIX 1 #endif #if defined(__LP64__) || defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) || defined(__s390x__) diff --git a/src/common/crypto_openssl.cpp b/src/common/crypto_openssl.cpp index be846b8..7a1e390 100644 --- a/src/common/crypto_openssl.cpp +++ b/src/common/crypto_openssl.cpp @@ -10,7 +10,7 @@ #define _X86INTRIN_H_INCLUDED #endif #include "winlite.h" -#elif defined(POSIX) +#elif IsPosix() #include #include #include @@ -397,7 +397,7 @@ void CCrypto::GenerateRandomBlock( void *pvDest, int cubDest ) bool bRtlGenRandomOK = s_pfnRtlGenRandom && ( s_pfnRtlGenRandom( pubDest, (unsigned long)cubDest ) == TRUE ); AssertFatal( bRtlGenRandomOK ); -#elif defined(POSIX) +#elif IsPosix() // Reading from /dev/urandom is threadsafe, but possibly slow due to a kernel // spinlock or mutex protecting access to the internal PRNG state. In theory, diff --git a/src/public/minbase/minbase_decls.h b/src/public/minbase/minbase_decls.h index 5c0e85e..585af7c 100644 --- a/src/public/minbase/minbase_decls.h +++ b/src/public/minbase/minbase_decls.h @@ -85,7 +85,7 @@ // Linux had a few areas where it didn't construct objects in the same order that Windows does. // So when CVProfile::CVProfile() would access g_pMemAlloc, it would crash because the allocator wasn't initalized yet. -#if defined( GNUC ) || defined ( COMPILER_GCC ) || defined( COMPILER_SNC ) +#if defined( __GNUC__ ) || defined ( COMPILER_GCC ) || defined( COMPILER_SNC ) #define CONSTRUCT_EARLY __attribute__((init_priority(101))) #else #define CONSTRUCT_EARLY @@ -93,7 +93,7 @@ #ifdef _WIN32 #define SELECTANY __declspec(selectany) -#elif defined(GNUC) || defined ( COMPILER_GCC ) || defined( COMPILER_SNC ) +#elif defined(__GNUC__) || defined ( COMPILER_GCC ) || defined( COMPILER_SNC ) #define SELECTANY __attribute__((weak)) #else #define SELECTANY static @@ -105,7 +105,7 @@ #if defined(_WIN32) && !defined(_XBOX) #define PLAT_DECL_EXPORT __declspec( dllexport ) #define PLAT_DECL_IMPORT __declspec( dllimport ) -#elif defined(GNUC) || defined(COMPILER_GCC) +#elif defined(__GNUC__) || defined(COMPILER_GCC) #define PLAT_DECL_EXPORT __attribute__((visibility("default"))) #define PLAT_DECL_IMPORT #elif defined(_XBOX) || defined(COMPILER_SNC) @@ -156,7 +156,7 @@ #define __stdcall __attribute__ ((__stdcall__)) #endif #define FASTCALL -#elif defined(POSIX) +#elif IsPosix() #define __stdcall #define __cdecl #define STDCALL @@ -167,7 +167,7 @@ #define NOINLINE __declspec(noinline) #define NORETURN __declspec(noreturn) #define FORCEINLINE __forceinline -#elif defined(GNUC) || defined(COMPILER_GCC) || defined(COMPILER_SNC) +#elif defined(__GNUC__) || defined(COMPILER_GCC) || defined(COMPILER_SNC) #define NOINLINE __attribute__ ((noinline)) #define NORETURN __attribute__ ((noreturn)) #if defined(COMPILER_GCC) || defined(COMPILER_SNC) diff --git a/src/public/minbase/minbase_identify.h b/src/public/minbase/minbase_identify.h index f73496e..b9e854d 100644 --- a/src/public/minbase/minbase_identify.h +++ b/src/public/minbase/minbase_identify.h @@ -48,10 +48,6 @@ #endif #endif -#if ( defined(LINUX) || defined(OSX) || defined(ANDROID) ) && !defined(POSIX) - #define POSIX -#endif - #if defined(_WIN32) && !defined(WINDED) #if defined(_M_IX86) #define __i386__ 1 @@ -110,6 +106,10 @@ #define IsRetail() false #endif +#ifdef IsPosix + #error "Too soon" +#endif + #ifdef _DEBUG #define IsRelease() false #define IsDebug() true @@ -122,29 +122,41 @@ #define IsXboxOne() true #define IsConsole() true #elif defined( NN_NINTENDO_SDK ) - #if !defined(POSIX) && !defined(_WIN32) - #define POSIX + #ifndef _WIN32 + #define IsPosix() true #endif #define IsNintendoSwitch() true #define IsConsole() true -#elif defined( _PS5 ) - #ifndef POSIX - #define POSIX - #endif +#elif defined( __PROSPERO__ ) + #define IsPosix() true #define IsPS5() true #define IsConsole() true +#elif defined( __ORBIS__ ) + #define IsPosix() true + #define IsPS4() true + #define IsConsole() true #elif defined( _WIN32 ) #define IsWindows() true #define IsPC() true -#elif defined(POSIX) - #define IsPC() true - #ifdef LINUX - #define IsLinux() true - #endif - #ifdef OSX +#elif defined( __ANDROID__ ) || defined( ANDROID ) + #define IsAndroid() true + #define IsPosix() true +#elif defined(__APPLE__) + #include + #if defined( TARGET_OS_MAC ) #define SUPPORTS_IOPOLLINGHELPER #define IsOSX() true + #define IsPosix() true + //#elif defined( TARGET_OS_IPHONE ) + #else + #error "Unsupported platform" #endif +#elif defined( LINUX ) || defined( __LINUX__ ) || defined(linux) || defined(__linux) || defined(__linux__) + #define IsLinux() true + #define IsPosix() true +#elif defined( _POSIX_VERSION ) || defined( POSIX ) || defined( VALVE_POSIX ) + #define IsPosix() true + #define IsPC() true #else #error Undefined platform #endif @@ -155,6 +167,9 @@ #ifndef IsPC #define IsPC() false #endif +#ifndef IsAndroid + #define IsAndroid() false +#endif #ifndef IsConsole #define IsConsole() false #endif @@ -164,15 +179,17 @@ #ifndef IsXboxOne #define IsXboxOne() false #endif +#ifndef IsPS4 + #define IsPS4() false +#endif #ifndef IsPS5 #define IsPS5() false #endif +#define IsPlaystation() ( IsPS4() || IsPS5() ) #ifndef IsLinux #define IsLinux() false #endif -#ifdef POSIX - #define IsPosix() true -#else +#ifndef IsPosix #define IsPosix() false #endif #ifndef IsOSX @@ -185,13 +202,6 @@ #define IsARM() false #endif #endif -#ifndef IsAndroid - #ifdef ANDROID - #define IsAndroid() true - #else - #define IsAndroid() false - #endif -#endif // Detect if RTTI is enabled in the current compile #if defined(__clang__) diff --git a/src/public/minbase/minbase_macros.h b/src/public/minbase/minbase_macros.h index 04c1f3b..bae371d 100644 --- a/src/public/minbase/minbase_macros.h +++ b/src/public/minbase/minbase_macros.h @@ -47,16 +47,18 @@ #if defined(_WIN32) #define PLAT_DLL_EXT "dll" -#elif defined(LINUX) +#elif IsLinux() #define PLAT_DLL_EXT "so" -#elif defined(OSX) +#elif IsOSX() #define PLAT_DLL_EXT "dylib" #endif #if defined(_WIN32) #define PLAT_PATH_SLASH "\\" -#elif defined(POSIX) +#elif IsPosix() #define PLAT_PATH_SLASH "/" +#else + #error "?" #endif #if defined( _PS3 ) @@ -64,7 +66,7 @@ #define PATH_MAX CELL_GAME_PATH_MAX #endif -#if (!defined(_WIN32) || defined(WINDED)) && defined(POSIX) +#if (!defined(_WIN32) || defined(WINDED)) && IsPosix() #define MAX_PATH PATH_MAX #define _MAX_PATH PATH_MAX #endif @@ -149,7 +151,7 @@ FORCEINLINE unsigned __int64 PLAT_CPU_TIME() } -#elif defined(POSIX) +#elif IsPosix() #include @@ -252,7 +254,7 @@ char (*RtlpNumberOf( UNALIGNED T (&)[N] ))[N]; #endif #endif -#elif defined(LINUX) +#elif IsLinux() // On Linux/gcc, RtlpNumberOf doesn't work well with pointers to structs // that are defined function locally. Here we have an alternative implementation @@ -318,7 +320,7 @@ struct ErrorIfIsPointerNotArrayGivenToARRAYSIZE #endif // Don't define for Windows, since it is defined unconditionally in winnt.h. -#if !defined( UNREFERENCED_PARAMETER ) && !defined( WIN32 ) +#if !defined( UNREFERENCED_PARAMETER ) && !defined( _WIN32 ) #define UNREFERENCED_PARAMETER(parm) NOTE_UNUSED(parm) #endif diff --git a/src/public/minbase/minbase_types.h b/src/public/minbase/minbase_types.h index 67f7491..0f35c5a 100644 --- a/src/public/minbase/minbase_types.h +++ b/src/public/minbase/minbase_types.h @@ -75,7 +75,7 @@ typedef uint32 uint32_t; // NOTE: int64_t must match the compiler stdint.h definition // and so may not match the Steam int64. Mixing the two is // error-prone so always use the Steam non-_t types in Steam code. -#if defined(COMPILER_GCC) && defined(PLATFORM_64BITS) && !defined(__MINGW32__) && !defined(OSX) && !(defined(IOS) || defined(TVOS)) +#if defined(COMPILER_GCC) && defined(PLATFORM_64BITS) && !defined(__MINGW32__) && !IsOSX() && !(defined(IOS) || defined(TVOS)) #define INT64_DIFFERENT_FROM_INT64_T 1 typedef long int int64_t; typedef unsigned long int uint64_t; diff --git a/src/public/minbase/minbase_warnings.h b/src/public/minbase/minbase_warnings.h index 8aef4b0..c535c84 100644 --- a/src/public/minbase/minbase_warnings.h +++ b/src/public/minbase/minbase_warnings.h @@ -30,7 +30,7 @@ #pragma GCC diagnostic ignored "-Wtype-limits" #endif -#if IsPS5() /* This is the wrong way to detect this. HALP */ +#if defined( __PROSPERO__ ) || defined( __ORBIS__ ) /* This is the wrong way to detect this. HALP */ #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wreorder-ctor" #endif diff --git a/src/public/tier0/platform.h b/src/public/tier0/platform.h index 17e4896..936d725 100644 --- a/src/public/tier0/platform.h +++ b/src/public/tier0/platform.h @@ -30,7 +30,7 @@ #include "minbase/minbase_macros.h" #include "minbase/minbase_endian.h" -#ifdef POSIX +#if IsPosix() typedef int SOCKET; #define INVALID_SOCKET (-1) #else @@ -53,7 +53,7 @@ #include "platformtime.h" -#if defined( POSIX ) +#if IsPosix() // handle mapping windows names used in tier0 to posix names in one place #define _snprintf snprintf //validator.cpp diff --git a/src/steamnetworkingsockets/steamnetworkingsockets_platform.h b/src/public/tier0/platform_sockets.h similarity index 70% rename from src/steamnetworkingsockets/steamnetworkingsockets_platform.h rename to src/public/tier0/platform_sockets.h index e4a4cd4..9978343 100644 --- a/src/steamnetworkingsockets/steamnetworkingsockets_platform.h +++ b/src/public/tier0/platform_sockets.h @@ -1,13 +1,34 @@ //====== Copyright Valve Corporation, All rights reserved. ==================== // -// Include the relevant platform-specific headers for socket-related stuff, -// and declare some functions make them look similar +// Include the relevant platform-specific headers for socket-related +// stuff, and declare some functions make them look as similar to +// plain BSD sockets as possible. +// +// This includes a bunch of stuff. DO NOT INCLUDE THIS FROM A HEADER // +// Some things that will be defined by this file: +// +// closesocket() +// GetLastSocketError() +// SetSocketNonBlocking() +// +// USE_EPOLL or USE_POLL +// If USE_EPOLL: +// EPollHandle, INVALID_EPOLL_HANDLE, EPollCreate() +// +// WAKE_THREAD_USING_EVENT or WAKE_THREAD_USING_SOCKET_PAIR +// If WAKE_THREAD_USING_EVENT: +// ThreadWakeEvent, INVALID_THREAD_WAKE_EVENT, SetWakeThreadEvent() -#ifndef STEAMNETWORKINGSOCKETS_PLATFORM_H -#define STEAMNETWORKINGSOCKETS_PLATFORM_H +#ifndef TIER0_PLATFORM_SOCKETS_H +#define TIER0_PLATFORM_SOCKETS_H #pragma once +#include "platform.h" + +// !KLUDGE! +typedef char SteamNetworkingErrMsg[ 1024 ]; + // Socket headers #ifdef _WIN32 //#include @@ -45,12 +66,11 @@ #elif IsNintendoSwitch() // NDA-protected material, so all this is in a separate file - #include "clientlib/nswitch/steamnetworkingsockets_platform_nswitch.h" -#elif IsPS5() + #include "platform_sockets_nswitch.h" +#elif IsPlaystation() // NDA-protected material, so all this is in a separate file - #include "clientlib/ps5/steamnetworkingsockets_platform_ps5.h" - -#else + #include "platform_sockets_playstation.h" +#elif IsPosix() // POSIX-ish platform (Linux, OSX, Android, IOS) #include @@ -61,7 +81,7 @@ #include #include - #ifndef ANDROID + #if !IsAndroid() #include #endif #include @@ -95,7 +115,7 @@ inline EPollHandle EPollCreate( SteamNetworkingErrMsg &errMsg ) { int flags = 0; - #ifdef LINUX + #if IsLinux() flags |= EPOLL_CLOEXEC; #endif EPollHandle e = epoll_create1( flags ); @@ -113,6 +133,8 @@ // instead of a socket pair? #endif +#else + #error "How do?" #endif -#endif // #ifndef STEAMNETWORKINGSOCKETS_PLATFORM_H +#endif // _H diff --git a/src/public/tier0/wchartypes.h b/src/public/tier0/wchartypes.h index 9b509c6..90e2933 100644 --- a/src/public/tier0/wchartypes.h +++ b/src/public/tier0/wchartypes.h @@ -31,7 +31,7 @@ typedef unsigned char uint8; typedef unsigned char BYTE; typedef unsigned char byte; -#ifdef WIN32 +#ifdef _WIN32 #include #include #elif defined( _PS3 ) @@ -85,7 +85,7 @@ typedef char tchar; #endif -#if defined( _MSC_VER ) || defined( WIN32 ) +#if defined( _MSC_VER ) || defined( _WIN32 ) typedef wchar_t uchar16; typedef unsigned int uchar32; #else diff --git a/src/public/tier1/fmtstr.h b/src/public/tier1/fmtstr.h index 9410241..1f94b7a 100644 --- a/src/public/tier1/fmtstr.h +++ b/src/public/tier1/fmtstr.h @@ -19,7 +19,7 @@ #pragma once #endif -#if defined(POSIX) +#ifdef __GNUC__ // clang will error if the symbol visibility for an object changes between static libraries (and/or your main dylib) // so force the FmtStr templates and importantly the global scAsserted below to hidden (i.e don't escape the dll) forcefully #pragma GCC visibility push(hidden) @@ -318,7 +318,7 @@ void CFmtStrN< SIZE_BUF, QT, ON_STACK >::Set( const char *pchValue, int nSize ) m_nLength = CopyStringLength( BaseClass::m_szBuf, pchValue, nMaxLength ); } -#if defined(POSIX) +#ifdef __GNUC__ #pragma GCC visibility pop #endif diff --git a/src/public/tier1/utliterator.h b/src/public/tier1/utliterator.h index d9fd645..9cc5a9c 100644 --- a/src/public/tier1/utliterator.h +++ b/src/public/tier1/utliterator.h @@ -13,7 +13,7 @@ // Forward declarations of tag types and some template helper classes //----------------------------------------------------------------------------- -#if !defined( OSX ) && !defined( IOS ) && !defined( TVOS ) && !defined(COMPILER_CLANG) +#if !IsOSX() && !defined( IOS ) && !defined( TVOS ) && !defined(COMPILER_CLANG) namespace std { struct forward_iterator_tag; diff --git a/src/public/vstdlib/strtools.h b/src/public/vstdlib/strtools.h index dd3eeb6..089638a 100644 --- a/src/public/vstdlib/strtools.h +++ b/src/public/vstdlib/strtools.h @@ -104,13 +104,13 @@ extern void V_StripTrailingWhitespaceASCII( char *pch ); // trim whitespace from both ends of the string extern int V_StrTrim( char *pStr ); -#ifdef POSIX -#ifdef ANDROID +#if IsPosix() +#if IsAndroid() #include #endif #define _atoi64 atoll #define _wtoi(arg) wcstol(arg, NULL, 10) -#ifdef ANDROID +#if IsAndroid() // TODO - Android doesn't support wcstoi64, so just use a basic implementation of our own. #define _wcstoi64 vstdlib_wcstoi64 #define _wcstoui64 vstdlib_wcstoui64 @@ -124,7 +124,7 @@ extern int V_StrTrim( char *pStr ); #define _strtoi64 strtoll #define _strtoui64 strtoull #define _vsnprintf vsnprintf -#if defined(OSX) || defined(ANDROID) +#if IsOSX() || IsAndroid() // TODO - OSX doesn't support wcscasecmp until 10.7, so just // use a basic implementation of our own. #define _wcsicmp vstdlib_wcsicmp @@ -139,7 +139,7 @@ extern int V_StrTrim( char *pStr ); #endif #define TEXT(str) str -#endif // POSIX +#endif // IsPosix() END_TIER0_NAMESPACE diff --git a/src/steamnetworkingsockets/clientlib/csteamnetworkingsockets.cpp b/src/steamnetworkingsockets/clientlib/csteamnetworkingsockets.cpp index e4b0d49..9eee4e6 100644 --- a/src/steamnetworkingsockets/clientlib/csteamnetworkingsockets.cpp +++ b/src/steamnetworkingsockets/clientlib/csteamnetworkingsockets.cpp @@ -2384,7 +2384,7 @@ const char *CSteamNetworkingUtils::GetBuildString() const char *CSteamNetworkingUtils::GetPlatformString() { - #if defined( NN_NINTENDO_SDK ) + #if IsNintendoSwitch() return "nswitch"; #elif defined( _GAMECORE ) // Is this right? This might actually require a system call. @@ -2392,11 +2392,11 @@ const char *CSteamNetworkingUtils::GetPlatformString() #elif defined( _STADIA ) // Not sure if this works. return "stadia"; - #elif defined( _XBOX_ONE ) + #elif IsXboxOne() return "xbone"; - #elif defined( _PS4 ) + #elif IsPS4() return "ps4"; - #elif defined( _PS5 ) + #elif IsPS5() return "ps5"; #elif defined( TVOS ) || defined( __TVOS__ ) return "tvos"; @@ -2408,13 +2408,13 @@ const char *CSteamNetworkingUtils::GetPlatformString() #else return "osx"; #endif - #elif defined( OSX ) + #elif IsOSX() return "osx"; - #elif defined( ANDROID ) || defined( __ANDROID__ ) + #elif IsAndroid() return "android"; #elif defined( _WINDOWS ) return "windows"; - #elif defined( LINUX ) || defined( __LINUX__ ) || defined(linux) || defined(__linux) || defined(__linux__) + #elif IsLinux() return "linux"; #elif defined( FREEBSD ) || defined( __FreeBSD__ ) return "freebsd"; diff --git a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_lowlevel.cpp b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_lowlevel.cpp index d0ccb36..b42872d 100644 --- a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_lowlevel.cpp +++ b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_lowlevel.cpp @@ -15,16 +15,8 @@ #include #include -#ifdef POSIX -#include -#include -#include -#include -#include -#endif - #include "steamnetworkingsockets_lowlevel.h" -#include "../steamnetworkingsockets_platform.h" +#include #include "../steamnetworkingsockets_internal.h" #include "../steamnetworkingsockets_thinker.h" #include "steamnetworkingsockets_connections.h" @@ -33,6 +25,18 @@ #include #include "crypto.h" +#if IsPosix() + #include + #include + #include + #if !IsNintendoSwitch() + #include + #endif + #ifdef STEAMNETWORKINGSOCKETS_ENABLE_RESOLVEHOSTNAME + #include + #endif +#endif + #include // Ugggggggggg MSVC VS2013 STL bug: try_lock_for doesn't actually respect the timeout, it always ends up using an infinite timeout. @@ -888,6 +892,33 @@ static void UpdateFakeRateLimitTokenBuckets( SteamNetworkingMicroseconds usecNow inline IRawUDPSocket::IRawUDPSocket() {} inline IRawUDPSocket::~IRawUDPSocket() {} + +// Perform gather-based send, on platform that doesn't have sendmsg +#ifdef PLATFORM_NO_SENDMSG +bool sendto_gather( int sockfd, int nChunks, const iovec *pChunks, sockaddr *pAddr, socklen_t addrSize ) +{ + COMPILE_TIME_ASSERT( k_cbSteamNetworkingSocketsMaxUDPMsgLen < 1500 ); + char pkt[ 2048 ]; + char *max = pkt + sizeof(pkt); + char *d = pkt; + for ( int i = 0 ; i < nChunks ; ++i ) + { + const iovec &chunk = pChunks[i]; + if ( d + chunk.iov_len > max ) + { + AssertMsg( false, "Gather send too big!" ); + return false; + } + memcpy( d, chunk.iov_base, chunk.iov_len ); + d += chunk.iov_len; + } + + ssize_t cbTotal = d - pkt; + ssize_t r = sendto( sockfd, pkt, cbTotal, 0, pAddr, addrSize ); + return ( r == cbTotal ); +} +#endif + class CRawUDPSocketImpl final : public IRawUDPSocket { public: @@ -917,6 +948,7 @@ public: inline bool BReallySendRawPacket( int nChunks, const iovec *pChunks, const netadr_t &adrTo ) const { Assert( m_socket != INVALID_SOCKET ); + Assert( nChunks > 0 ); // Add a tag. If we end up holding the lock for a long time, this tag // will tell us how many packets were sent @@ -927,8 +959,13 @@ public: socklen_t addrSize; if ( m_nAddressFamilies & k_nAddressFamily_IPv6 ) { - addrSize = sizeof(sockaddr_in6); - adrTo.ToSockadrIPV6( &destAddress ); + #ifdef PLATFORM_NO_IPV6 + Assert( false ); + return false; + #else + addrSize = sizeof(sockaddr_in6); + adrTo.ToSockadrIPV6( &destAddress ); + #endif } else { @@ -953,7 +990,7 @@ public: SteamNetworkingMicroseconds usecSendStart = SteamNetworkingSockets_GetLocalTimestamp(); #endif - #ifdef WIN32 + #ifdef _WIN32 // Confirm that iovec and WSABUF are indeed bitwise equivalent COMPILE_TIME_ASSERT( sizeof( iovec ) == sizeof( WSABUF ) ); COMPILE_TIME_ASSERT( offsetof( iovec, iov_len ) == offsetof( WSABUF, len ) ); @@ -992,17 +1029,30 @@ public: } #endif #else - msghdr msg; - msg.msg_name = (sockaddr *)&destAddress; - msg.msg_namelen = addrSize; - msg.msg_iov = const_cast( pChunks ); - msg.msg_iovlen = nChunks; - msg.msg_control = nullptr; - msg.msg_controllen = 0; - msg.msg_flags = 0; + bool bResult; + if ( nChunks == 1 ) + { + ssize_t r = sendto( m_socket, pChunks->iov_base, pChunks->iov_len, 0, (sockaddr *)&destAddress, addrSize ); + bResult = ( r == (ssize_t)pChunks->iov_len ); + } + else + { + #ifdef PLATFORM_NO_SENDMSG + bResult = sendto_gather( m_socket, nChunks, pChunks, (sockaddr *)&destAddress, addrSize ); + #else + msghdr msg; + msg.msg_name = (sockaddr *)&destAddress; + msg.msg_namelen = addrSize; + msg.msg_iov = const_cast( pChunks ); + msg.msg_iovlen = nChunks; + msg.msg_control = nullptr; + msg.msg_controllen = 0; + msg.msg_flags = 0; - int r = ::sendmsg( m_socket, &msg, 0 ); - bool bResult = ( r >= 0 ); // just check for -1 for error, since we don't want to take the time here to scan the iovec and sum up the expected total number of bytes sent + ssize_t r = sendmsg( m_socket, &msg, 0 ); + bResult = ( r >= 0 ); // just check for -1 for error, since we don't want to take the time here to scan the iovec and sum up the expected total number of bytes sent + #endif + } #endif #ifdef STEAMNETWORKINGSOCKETS_LOWLEVEL_TIME_SOCKET_CALLS @@ -1284,6 +1334,11 @@ static CPacketLaggerRecv s_packetLagQueueRecv; #ifdef USE_POLL static CUtlVector s_vecPollFDs; static bool s_bRecreatePollList = true; + +#ifndef POLLEVENT_INVALID + #define POLLEVENT_INVALID (-1) +#endif + #endif #ifdef USE_EPOLL @@ -1461,16 +1516,16 @@ void CRawUDPSocketImpl::Close() } } -static SOCKET OpenUDPSocketBoundToSockAddr( const void *sockaddr, size_t len, SteamNetworkingErrMsg &errMsg, int *pnIPv6AddressFamilies, int nBindInterface = -1 ) +static SOCKET OpenUDPSocketBoundToSockAddr( const void *pSockaddr, size_t len, SteamNetworkingErrMsg &errMsg, int *pnIPv6AddressFamilies, int nBindInterface = -1 ) { unsigned int opt; - const sockaddr_in *inaddr = (const sockaddr_in *)sockaddr; + const sockaddr_in *inaddr = (const sockaddr_in *)pSockaddr; // Select socket type. For linux, use the "close on exec" flag, so that the // socket will not be inherited by any child process that we spawn. int sockType = SOCK_DGRAM; - #ifdef LINUX + #if IsLinux() sockType |= SOCK_CLOEXEC; #endif #if IsNintendoSwitch() && !defined( _WIN32 ) @@ -1514,36 +1569,43 @@ static SOCKET OpenUDPSocketBoundToSockAddr( const void *sockaddr, size_t len, St // Handle IP v6 dual stack? if ( pnIPv6AddressFamilies ) { + #ifdef PLATFORM_NO_IPV6 + Assert( false ); // Caller should check this define + V_strcpy_safe( errMsg, "No IPV6 support" ); + closesocket( sock ); + return INVALID_SOCKET; + #else - // Enable dual stack? - opt = ( *pnIPv6AddressFamilies == k_nAddressFamily_IPv6 ) ? 1 : 0; - if ( setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, sizeof( opt ) ) != 0 ) - { - if ( *pnIPv6AddressFamilies == k_nAddressFamily_IPv6 ) + // Enable dual stack? + opt = ( *pnIPv6AddressFamilies == k_nAddressFamily_IPv6 ) ? 1 : 0; + if ( setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, sizeof( opt ) ) != 0 ) { - // Spew a warning, but continue - SpewWarning( "Failed to set socket for IPv6 only (IPV6_V6ONLY=1). Error code 0x%08X. Continuing anyway.\n", GetLastSocketError() ); + if ( *pnIPv6AddressFamilies == k_nAddressFamily_IPv6 ) + { + // Spew a warning, but continue + SpewWarning( "Failed to set socket for IPv6 only (IPV6_V6ONLY=1). Error code 0x%08X. Continuing anyway.\n", GetLastSocketError() ); + } + else + { + // Dual stack required, or only requested? + if ( *pnIPv6AddressFamilies == k_nAddressFamily_DualStack ) + { + V_sprintf_safe( errMsg, "Failed to set socket for dual stack (IPV6_V6ONLY=0). Error code 0x%08X.", GetLastSocketError() ); + closesocket( sock ); + return INVALID_SOCKET; + } + + // Let caller know we're IPv6 only, and spew about this. + SpewWarning( "Failed to set socket for dual stack (IPV6_V6ONLY=0). Error code 0x%08X. Continuing using IPv6 only!\n", GetLastSocketError() ); + *pnIPv6AddressFamilies = k_nAddressFamily_IPv6; + } } else { - // Dual stack required, or only requested? - if ( *pnIPv6AddressFamilies == k_nAddressFamily_DualStack ) - { - V_sprintf_safe( errMsg, "Failed to set socket for dual stack (IPV6_V6ONLY=0). Error code 0x%08X.", GetLastSocketError() ); - closesocket( sock ); - return INVALID_SOCKET; - } - - // Let caller know we're IPv6 only, and spew about this. - SpewWarning( "Failed to set socket for dual stack (IPV6_V6ONLY=0). Error code 0x%08X. Continuing using IPv6 only!\n", GetLastSocketError() ); - *pnIPv6AddressFamilies = k_nAddressFamily_IPv6; + // Tell caller what they've got + *pnIPv6AddressFamilies = opt ? k_nAddressFamily_IPv6 : k_nAddressFamily_DualStack; } - } - else - { - // Tell caller what they've got - *pnIPv6AddressFamilies = opt ? k_nAddressFamily_IPv6 : k_nAddressFamily_DualStack; - } + #endif } // Bind to particular interface @@ -1586,7 +1648,7 @@ static SOCKET OpenUDPSocketBoundToSockAddr( const void *sockaddr, size_t len, St } // Bind it to specific desired local port/IP - if ( bind( sock, (struct sockaddr *)sockaddr, (socklen_t)len ) == -1 ) + if ( bind( sock, (struct sockaddr *)pSockaddr, (socklen_t)len ) == -1 ) { V_sprintf_safe( errMsg, "Failed to bind socket. Error code 0x%08X.", GetLastSocketError() ); closesocket( sock ); @@ -1659,31 +1721,33 @@ static CRawUDPSocketImpl *OpenRawUDPSocketInternal( CRecvPacketCallback callback // Try IPv6? SOCKET sock = INVALID_SOCKET; - if ( nAddressFamilies & k_nAddressFamily_IPv6 ) - { - sockaddr_in6 address6; - memset( &address6, 0, sizeof(address6) ); - address6.sin6_family = AF_INET6; - memcpy( address6.sin6_addr.s6_addr, addrLocal.m_ipv6, 16 ); - address6.sin6_port = BigWord( addrLocal.m_port ); - - // Try to get socket - int nIPv6AddressFamilies = nAddressFamilies; - sock = OpenUDPSocketBoundToSockAddr( &address6, sizeof(address6), errMsg, &nIPv6AddressFamilies, nBindInterface ); - - if ( sock == INVALID_SOCKET ) + #ifndef PLATFORM_NO_IPV6 + if ( nAddressFamilies & k_nAddressFamily_IPv6 ) { - // Allowing fallback to IPv4? - if ( nAddressFamilies != k_nAddressFamily_Auto ) - return nullptr; + sockaddr_in6 address6; + memset( &address6, 0, sizeof(address6) ); + address6.sin6_family = AF_INET6; + memcpy( address6.sin6_addr.s6_addr, addrLocal.m_ipv6, 16 ); + address6.sin6_port = BigWord( addrLocal.m_port ); - // Continue below, we'll try IPv4 + // Try to get socket + int nIPv6AddressFamilies = nAddressFamilies; + sock = OpenUDPSocketBoundToSockAddr( &address6, sizeof(address6), errMsg, &nIPv6AddressFamilies, nBindInterface ); + + if ( sock == INVALID_SOCKET ) + { + // Allowing fallback to IPv4? + if ( nAddressFamilies != k_nAddressFamily_Auto ) + return nullptr; + + // Continue below, we'll try IPv4 + } + else + { + nAddressFamilies = nIPv6AddressFamilies; + } } - else - { - nAddressFamilies = nIPv6AddressFamilies; - } - } + #endif // Try IPv4? if ( sock == INVALID_SOCKET ) @@ -1721,11 +1785,13 @@ static CRawUDPSocketImpl *OpenRawUDPSocketInternal( CRecvPacketCallback callback const sockaddr_in *boundaddr4 = (const sockaddr_in *)&addrBound; addrLocal.SetIPv4( BigDWord( boundaddr4->sin_addr.s_addr ), BigWord( boundaddr4->sin_port ) ); } + #ifndef PLATFORM_NO_IPV6 else if ( addrBound.ss_family == AF_INET6 ) { const sockaddr_in6 *boundaddr6 = (const sockaddr_in6 *)&addrBound; addrLocal.SetIPv6( boundaddr6->sin6_addr.s6_addr, BigWord( boundaddr6->sin6_port ) ); } + #endif else { Assert( false ); @@ -1978,7 +2044,7 @@ static bool PollRawUDPSockets( int nMaxTimeoutMS, bool bManualPoll ) Assert( f != INVALID_SOCKET ); \ p.fd = f; \ p.events = POLLRDNORM; \ - p.revents = -1; /* Make sure kernel is clearing events properly */ \ + p.revents = POLLEVENT_INVALID; /* Make sure kernel is clearing events properly */ \ } for ( CRawUDPSocketImpl *pSock: s_vecRawSockets ) @@ -2015,7 +2081,7 @@ static bool PollRawUDPSockets( int nMaxTimeoutMS, bool bManualPoll ) struct epoll_event epoll_events[ 32 ]; int num_epoll_events = epoll_wait( s_epollfd, epoll_events, V_ARRAYSIZE( epoll_events ), nMaxTimeoutMS ); #elif defined( USE_POLL ) - poll( s_vecPollFDs.Base(), s_vecPollFDs.Count(), nMaxTimeoutMS ); + int poll_result = poll( s_vecPollFDs.Base(), s_vecPollFDs.Count(), nMaxTimeoutMS ); #elif defined( _WIN32 ) WaitForSingleObject( s_hEventWakeThread, nMaxTimeoutMS ); #else @@ -2099,6 +2165,41 @@ static bool PollRawUDPSockets( int nMaxTimeoutMS, bool bManualPoll ) #else + // On POSIX, check return value, and also handle the wake "fd" + #ifdef USE_POLL + { + + // Make sure we actually got some descriptors with data + if ( poll_result <= 0 ) + { + if ( poll_result < 0 ) + SpewWarning( "poll() returned %d, errno %d\n", poll_result, errno ); + goto exit_polling; + } + + pollfd &wake = s_vecPollFDs[ nSocketsToPoll ]; + if ( (int)( wake.revents & POLLRDNORM ) ) + { + Assert( wake.revents != POLLEVENT_INVALID ); + #if defined( WAKE_THREAD_USING_EVENT ) + Assert( wake.fd == s_hEventWakeThread ); + ClearWakeThreadEvent( wake, s_hEventWakeThread ); + #elif defined( WAKE_THREAD_USING_SOCKET_PAIR ) + Assert( wake.fd == s_hSockWakeThreadRead ); + + // Just eat one request for now. + // I think it's probably safe to eat all of them, but + // it's a small optimization and I don't want to debug + // it is that's not true. + char buf[8]; + ::recv( s_hSockWakeThreadRead, buf, sizeof(buf), 0 ); + #else + #error "How did we wake up?" + #endif + } + } + #endif + // Not using epoll, just check all sockets for ( int idx = 0 ; idx < nSocketsToPoll ; ++idx ) { @@ -2117,7 +2218,7 @@ static bool PollRawUDPSockets( int nMaxTimeoutMS, bool bManualPoll ) #elif defined( USE_POLL ) if ( !( s_vecPollFDs[ idx ].revents & POLLRDNORM ) ) continue; - Assert( s_vecPollFDs[ idx ].revents != -1 ); // Make sure kernel actually populated this + Assert( s_vecPollFDs[ idx ].revents != POLLEVENT_INVALID ); // Make sure kernel actually populated this #else #error "How to tell if we need to drain socket?" #endif @@ -2127,32 +2228,6 @@ static bool PollRawUDPSockets( int nMaxTimeoutMS, bool bManualPoll ) if ( !DrainSocket( pSock ) ) goto exit_polling; } - - // On POSIX, check for draining the thread wake "socket" - #ifdef USE_POLL - { - pollfd &wake = s_vecPollFDs[ nSocketsToPoll ]; - if ( wake.revents & POLLRDNORM ) - { - Assert( wake.revents != -1 ); - #if defined( WAKE_THREAD_USING_EVENT ) - Assert( wake.fd == s_hEventWakeThread ); - ClearWakeThreadEvent( wake, s_hEventWakeThread ) - #elif defined( WAKE_THREAD_USING_SOCKET_PAIR ) - Assert( wake.fd == s_hSockWakeThreadRead ); - - // Just eat one request for now. - // I think it's probably safe to eat all of them, but - // it's a small optimization and I don't want to debug - // it is that's not true. - char buf[8]; - ::recv( s_hSockWakeThreadRead, buf, sizeof(buf), 0 ); - #else - #error "How did we wake up?" - #endif - } - } - #endif #endif // USE_EPOLL, else exit_polling: @@ -2687,7 +2762,7 @@ static void SteamNetworkingThreadProc() // for packets to arrive. #if defined(_WIN32) DbgVerify( SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST ) ); - #elif defined(POSIX) + #elif IsPosix() // This probably won't work on Linux, because you cannot raise thread priority // without being root. But on some systems it works. So we try, and if it // works, great. @@ -3222,7 +3297,7 @@ bool BSteamNetworkingSocketsLowLevelAddRef( SteamNetworkingErrMsg &errMsg ) V_sprintf_safe( errMsg, "nn::socket::EventFd. Error code 0x%08x.", GetLastError() ); return false; } - #elif IsPS5() + #elif IsPlaystation() // No additional setup needed here #else { @@ -3230,7 +3305,7 @@ bool BSteamNetworkingSocketsLowLevelAddRef( SteamNetworkingErrMsg &errMsg ) Assert( s_hSockWakeThreadWrite == INVALID_SOCKET ); int sockType = SOCK_DGRAM; - #ifdef LINUX + #if IsLinux() sockType |= SOCK_CLOEXEC; #endif int sock[2]; @@ -3344,7 +3419,7 @@ void SteamNetworkingSocketsLowLevelDecRef() nn::socket::Close( s_hEventWakeThread ); s_hEventWakeThread = INVALID_SOCKET; } - #elif IsPS5() + #elif IsPlaystation() // Nothing to do here #else if ( s_hSockWakeThreadRead != INVALID_SOCKET ) diff --git a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_p2p_ice.cpp b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_p2p_ice.cpp index 3ccb0b0..9592e56 100644 --- a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_p2p_ice.cpp +++ b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_p2p_ice.cpp @@ -22,7 +22,7 @@ #undef min #undef max #endif -#if defined( POSIX ) && defined( STEAMNETWORKINGSOCKETS_ENABLE_WEBRTC ) +#if IsPosix() && defined( STEAMNETWORKINGSOCKETS_ENABLE_WEBRTC ) #include #endif @@ -309,8 +309,8 @@ void CSteamNetworkConnectionP2P::CheckInitICE() return; } g_SteamNetworkingSockets_CreateICESessionFunc = (CreateICESession_t)::GetProcAddress( h, pszExportFunc ); - #elif defined( POSIX ) - #if defined( OSX ) || defined( IOS ) || defined( TVOS ) + #elif IsPosix() + #if IsOSX() || defined( IOS ) || defined( TVOS ) static const char pszModule[] = "libsteamwebrtc.dylib"; #else static const char pszModule[] = "libsteamwebrtc.so"; diff --git a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_stun.cpp b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_stun.cpp index e0e12da..d26ef21 100644 --- a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_stun.cpp +++ b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_stun.cpp @@ -8,7 +8,7 @@ #ifdef STEAMNETWORKINGSOCKETS_ENABLE_ICE #include "csteamnetworkingsockets.h" -#include "../steamnetworkingsockets_platform.h" +#include #include "crypto.h" // Put everything in a namespace, so we don't violate the one definition rule diff --git a/src/tier0/dbg.cpp b/src/tier0/dbg.cpp index 0421f76..dd31cc3 100644 --- a/src/tier0/dbg.cpp +++ b/src/tier0/dbg.cpp @@ -22,26 +22,30 @@ using namespace SteamNetworkingSocketsLib; #include -#ifdef POSIX +#if IsPosix() #include - #if !IsPS5() + #if !IsPlaystation() #include #endif #endif // POSIX -#ifdef LINUX +#if IsLinux() #include #endif -#ifdef OSX +#if IsOSX() #include #endif +#if IsPlaystation() && defined(_DEBUG) +// NDA material +#endif + bool Plat_IsInDebugSession() { #ifdef _WIN32 return (IsDebuggerPresent() != 0); -#elif defined(OSX) +#elif IsOSX() int mib[4]; struct kinfo_proc info; size_t size; @@ -53,7 +57,7 @@ bool Plat_IsInDebugSession() info.kp_proc.p_flag = 0; sysctl(mib,4,&info,&size,NULL,0); return ((info.kp_proc.p_flag & P_TRACED) == P_TRACED); -#elif defined(LINUX) +#elif IsLinux() static FILE *fp; if ( !fp ) { @@ -80,15 +84,12 @@ bool Plat_IsInDebugSession() } } return (nTracePid != 0); -#elif IsPS5() - // There might be a way to tell. Do we care? +#elif IsPlaystation() + // NDA material +#elif IsNintendoSwitch() return false; -#elif defined( _PS3 ) - #ifdef _CERT - return false; - #else - return snIsDebuggerPresent(); - #endif +#else + #error "HALP" #endif } diff --git a/src/tier0/platformtime.cpp b/src/tier0/platformtime.cpp index 14bf469..c1300fd 100644 --- a/src/tier0/platformtime.cpp +++ b/src/tier0/platformtime.cpp @@ -9,16 +9,20 @@ #else #include #include - #if defined OSX + #if IsOSX() #include #include #endif #endif +#if IsNintendoSwitch() + // NDA material +#endif + BEGIN_TIER0_NAMESPACE -#if defined( _WIN32 ) || IsOSX() +#if defined( _WIN32 ) || IsOSX() || IsNintendoSwitch() static uint64 g_TickFrequency; static double g_TickFrequencyDouble; static double g_TicksToUS; @@ -59,6 +63,8 @@ static uint64 InitTicks() g_TickFrequencyDouble = (double) TimebaseInfo.denom / (double) TimebaseInfo.numer * 1.0e9; g_TickFrequency = (uint64)( g_TickFrequencyDouble + 0.5 ); g_TickBase = mach_absolute_time(); +#elif IsNintendoSwitch() + // NDA material #elif IsPosix() // TickFrequency is constant since clock_gettime always returns nanoseconds timespec TimeSpec; @@ -68,7 +74,7 @@ static uint64 InitTicks() #error Unknown platform #endif - #if defined( _WIN32 ) || defined( OSX ) + #if defined( _WIN32 ) || IsOSX() || IsNintendoSwitch() g_TicksToUS = 1.0e6 / g_TickFrequencyDouble; #endif @@ -97,6 +103,8 @@ uint64 Plat_RelativeTicks() } #elif IsOSX() Ticks = mach_absolute_time(); +#elif IsNintendoSwitch() + // NDA material #elif IsPosix() timespec TimeSpec; clock_gettime( CLOCK_MONOTONIC, &TimeSpec ); diff --git a/src/tier1/netadr.cpp b/src/tier1/netadr.cpp index 5e4065f..aefee20 100644 --- a/src/tier1/netadr.cpp +++ b/src/tier1/netadr.cpp @@ -3,14 +3,7 @@ #include #include - -#ifdef WIN32 - #include - #undef SetPort -#else - #include - #include -#endif +#include #include #include "ipv6text.h" @@ -456,6 +449,7 @@ bool CIPAddress::SetFromSockadr(const void *addr, size_t addr_size, uint16 *punP return true; } +#ifndef PLATFORM_NO_IPV6 case AF_INET6: { if ( addr_size < sizeof(sockaddr_in6) ) @@ -473,6 +467,7 @@ bool CIPAddress::SetFromSockadr(const void *addr, size_t addr_size, uint16 *punP return true; } +#endif } return false; } @@ -686,6 +681,7 @@ size_t CIPAndPort::ToSockadr(void *addr, size_t addr_size) const } break; +#ifndef PLATFORM_NO_IPV6 case k_EIPTypeV6: { if ( addr_size < sizeof(sockaddr_in6) ) @@ -702,6 +698,7 @@ size_t CIPAndPort::ToSockadr(void *addr, size_t addr_size) const struct_size = sizeof(sockaddr_in6); } break; +#endif // #ifndef PLATFORM_NO_IPV6 } return struct_size; @@ -713,6 +710,7 @@ size_t CIPAndPort::ToSockadr(void *addr, size_t addr_size) const //----------------------------------------------------------------------------- // Purpose: Convert to an ipv6 sockaddr structure //----------------------------------------------------------------------------- +#ifndef PLATFORM_NO_IPV6 void CIPAndPort::ToSockadrIPV6(void *addr, size_t addr_size) const { memset( addr, 0, addr_size); @@ -728,3 +726,4 @@ void CIPAndPort::ToSockadrIPV6(void *addr, size_t addr_size) const s->sin6_scope_id = m_unIPv6Scope; s->sin6_port = BigWord( m_usPort ); } +#endif // PLATFORM_NO_IPV6 diff --git a/src/vstdlib/strtools.cpp b/src/vstdlib/strtools.cpp index 3808036..6376038 100644 --- a/src/vstdlib/strtools.cpp +++ b/src/vstdlib/strtools.cpp @@ -8,7 +8,7 @@ #include "winlite.h" #endif -#ifdef POSIX +#if IsPosix() #include #endif