#include #include #include #include #include #include #include "../public/common/TracySocket.hpp" #include "../public/common/TracyVersion.hpp" #include "GitRef.hpp" #include "HttpRequest.hpp" #if defined _WIN32 # include extern "C" typedef LONG (WINAPI *t_RtlGetVersion)( PRTL_OSVERSIONINFOW ); extern "C" typedef char* (WINAPI *t_WineGetVersion)(); extern "C" typedef char* (WINAPI *t_WineGetBuildId)(); #elif defined __linux__ # include #elif defined __APPLE__ # include "TargetConditionals.h" #endif static constexpr char CRLF[2] = { '\r', '\n' }; static const char* GetOsInfo() { static char buf[1024]; #if defined _WIN32 t_RtlGetVersion RtlGetVersion = (t_RtlGetVersion)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "RtlGetVersion" ); if( !RtlGetVersion ) { # ifdef __MINGW32__ sprintf( buf, "Windows (MingW)" ); # else sprintf( buf, "Windows" ); # endif } else { RTL_OSVERSIONINFOW ver = { sizeof( RTL_OSVERSIONINFOW ) }; RtlGetVersion( &ver ); # ifdef __MINGW32__ sprintf( buf, "Windows %i.%i.%i (MingW)", (int)ver.dwMajorVersion, (int)ver.dwMinorVersion, (int)ver.dwBuildNumber ); # else auto WineGetVersion = (t_WineGetVersion)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "wine_get_version" ); auto WineGetBuildId = (t_WineGetBuildId)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "wine_get_build_id" ); if( WineGetVersion && WineGetBuildId ) { sprintf( buf, "Windows %i.%i.%i (Wine %s [%s])", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, WineGetVersion(), WineGetBuildId() ); } else { sprintf( buf, "Windows %i.%i.%i", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber ); } # endif } #elif defined __linux__ struct utsname utsName; uname( &utsName ); # if defined __ANDROID__ sprintf( buf, "Linux %s (Android)", utsName.release ); # else sprintf( buf, "Linux %s", utsName.release ); # endif #elif defined __APPLE__ # if TARGET_OS_IPHONE == 1 sprintf( buf, "Darwin (iOS)" ); # elif TARGET_OS_MAC == 1 sprintf( buf, "Darwin (OSX)" ); # else sprintf( buf, "Darwin (unknown)" ); # endif #elif defined __DragonFly__ sprintf( buf, "BSD (DragonFly)" ); #elif defined __FreeBSD__ sprintf( buf, "BSD (FreeBSD)" ); #elif defined __NetBSD__ sprintf( buf, "BSD (NetBSD)" ); #elif defined __OpenBSD__ sprintf( buf, "BSD (OpenBSD)" ); #elif defined __QNX__ sprintf( buf, "QNX" ); #else sprintf( buf, "unknown" ); #endif return buf; } static std::atomic s_abort { false }; void HttpRequestAbort() { s_abort.store( true, std::memory_order_relaxed ); } void HttpRequest( const char* server, const char* resource, int port, const std::function& cb ) { tracy::Socket sock; for(;;) { if( s_abort.load( std::memory_order_relaxed ) ) return; if( sock.Connect( server, port ) ) break; if( !sock.IsConnecting() ) return; std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); } char request[4096]; const auto len = sprintf( request, "GET %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: Tracy Profiler %i.%i.%i (%s) [%s]\r\nConnection: close\r\nCache-Control: no-cache, no-store, must-revalidate\r\n\r\n", resource, server, tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch, GetOsInfo(), tracy::GitRef ); sock.Send( request, len ); char response[4096]; const auto sz = sock.ReadUpTo( response, 4096, 15, [] { return s_abort.load( std::memory_order_relaxed ); } ); if( sz < 13 ) return; if( memcmp( response, "HTTP/1.1 200", 12 ) != 0 ) return; auto hdr = response + 13; const char* hdrEnd = response + sz; int contentLength = 0; for(;;) { while( hdr + 2 <= hdrEnd && memcmp( hdr, CRLF, 2 ) != 0 ) hdr++; if( hdr + 2 > hdrEnd ) return; hdr += 2; if( hdr + 16 <= hdrEnd && memcmp( hdr, "Content-Length: ", 16 ) == 0 ) { hdr += 16; contentLength = atoi( hdr ); break; } } if( contentLength <= 0 ) return; for(;;) { while( hdr + 2 <= hdrEnd && memcmp( hdr, CRLF, 2 ) != 0 ) hdr++; if( hdr + 2 > hdrEnd ) return; hdr += 2; if( hdr + 2 <= hdrEnd && memcmp( hdr, CRLF, 2 ) == 0 ) { hdr += 2; break; } hdr += 2; } const auto hdrSize = hdr - response; const auto partSize = sz - hdrSize; char* data = new char[contentLength]; memcpy( data, hdr, partSize ); auto remaining = contentLength - partSize; if( remaining > 0 && !sock.Read( data + partSize, remaining, 15, [] { return s_abort.load( std::memory_order_relaxed ); } ) ) return; cb( contentLength, data ); }