The open source OpenXR runtime
at main 749 lines 17 kB view raw
1#include <assert.h> 2#include <inttypes.h> 3#include <new> 4#include <stdio.h> 5#include <stdlib.h> 6#include <string.h> 7#include <sys/types.h> 8 9#include "TracyAlloc.hpp" 10#include "TracySocket.hpp" 11#include "TracySystem.hpp" 12 13#ifdef _WIN32 14# ifndef NOMINMAX 15# define NOMINMAX 16# endif 17# include <winsock2.h> 18# include <ws2tcpip.h> 19# ifdef _MSC_VER 20# pragma warning(disable:4244) 21# pragma warning(disable:4267) 22# endif 23# define poll WSAPoll 24#else 25# include <arpa/inet.h> 26# include <sys/socket.h> 27# include <sys/param.h> 28# include <errno.h> 29# include <fcntl.h> 30# include <netinet/in.h> 31# include <netdb.h> 32# include <unistd.h> 33# include <poll.h> 34#endif 35 36#ifndef MSG_NOSIGNAL 37# define MSG_NOSIGNAL 0 38#endif 39 40namespace tracy 41{ 42 43#ifdef _WIN32 44typedef SOCKET socket_t; 45#else 46typedef int socket_t; 47#endif 48 49#ifdef _WIN32 50struct __wsinit 51{ 52 __wsinit() 53 { 54 WSADATA wsaData; 55 if( WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) != 0 ) 56 { 57 fprintf( stderr, "Cannot init winsock.\n" ); 58 exit( 1 ); 59 } 60 } 61}; 62 63void InitWinSock() 64{ 65 static __wsinit init; 66} 67#endif 68 69 70enum { BufSize = 128 * 1024 }; 71 72Socket::Socket() 73 : m_buf( (char*)tracy_malloc( BufSize ) ) 74 , m_bufPtr( nullptr ) 75 , m_sock( -1 ) 76 , m_bufLeft( 0 ) 77 , m_ptr( nullptr ) 78{ 79#ifdef _WIN32 80 InitWinSock(); 81#endif 82} 83 84Socket::Socket( int sock ) 85 : m_buf( (char*)tracy_malloc( BufSize ) ) 86 , m_bufPtr( nullptr ) 87 , m_sock( sock ) 88 , m_bufLeft( 0 ) 89 , m_ptr( nullptr ) 90{ 91} 92 93Socket::~Socket() 94{ 95 tracy_free( m_buf ); 96 if( m_sock.load( std::memory_order_relaxed ) != -1 ) 97 { 98 Close(); 99 } 100 if( m_ptr ) 101 { 102 freeaddrinfo( m_res ); 103#ifdef _WIN32 104 closesocket( m_connSock ); 105#else 106 close( m_connSock ); 107#endif 108 } 109} 110 111bool Socket::Connect( const char* addr, uint16_t port ) 112{ 113 assert( !IsValid() ); 114 115 if( m_ptr ) 116 { 117 const auto c = connect( m_connSock, m_ptr->ai_addr, m_ptr->ai_addrlen ); 118 if( c == -1 ) 119 { 120#if defined _WIN32 121 const auto err = WSAGetLastError(); 122 if( err == WSAEALREADY || err == WSAEINPROGRESS ) return false; 123 if( err != WSAEISCONN ) 124 { 125 freeaddrinfo( m_res ); 126 closesocket( m_connSock ); 127 m_ptr = nullptr; 128 return false; 129 } 130#else 131 const auto err = errno; 132 if( err == EALREADY || err == EINPROGRESS ) return false; 133 if( err != EISCONN ) 134 { 135 freeaddrinfo( m_res ); 136 close( m_connSock ); 137 m_ptr = nullptr; 138 return false; 139 } 140#endif 141 } 142 143#if defined _WIN32 144 u_long nonblocking = 0; 145 ioctlsocket( m_connSock, FIONBIO, &nonblocking ); 146#else 147 int flags = fcntl( m_connSock, F_GETFL, 0 ); 148 fcntl( m_connSock, F_SETFL, flags & ~O_NONBLOCK ); 149#endif 150 m_sock.store( m_connSock, std::memory_order_relaxed ); 151 freeaddrinfo( m_res ); 152 m_ptr = nullptr; 153 return true; 154 } 155 156 struct addrinfo hints; 157 struct addrinfo *res, *ptr; 158 159 memset( &hints, 0, sizeof( hints ) ); 160 hints.ai_family = AF_UNSPEC; 161 hints.ai_socktype = SOCK_STREAM; 162 163 char portbuf[32]; 164 sprintf( portbuf, "%" PRIu16, port ); 165 166 if( getaddrinfo( addr, portbuf, &hints, &res ) != 0 ) return false; 167 int sock = 0; 168 for( ptr = res; ptr; ptr = ptr->ai_next ) 169 { 170 if( ( sock = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ) ) == -1 ) continue; 171#if defined __APPLE__ 172 int val = 1; 173 setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) ); 174#endif 175#if defined _WIN32 176 u_long nonblocking = 1; 177 ioctlsocket( sock, FIONBIO, &nonblocking ); 178#else 179 int flags = fcntl( sock, F_GETFL, 0 ); 180 fcntl( sock, F_SETFL, flags | O_NONBLOCK ); 181#endif 182 if( connect( sock, ptr->ai_addr, ptr->ai_addrlen ) == 0 ) 183 { 184 break; 185 } 186 else 187 { 188#if defined _WIN32 189 const auto err = WSAGetLastError(); 190 if( err != WSAEWOULDBLOCK ) 191 { 192 closesocket( sock ); 193 continue; 194 } 195#else 196 if( errno != EINPROGRESS ) 197 { 198 close( sock ); 199 continue; 200 } 201#endif 202 } 203 m_res = res; 204 m_ptr = ptr; 205 m_connSock = sock; 206 return false; 207 } 208 freeaddrinfo( res ); 209 if( !ptr ) return false; 210 211#if defined _WIN32 212 u_long nonblocking = 0; 213 ioctlsocket( sock, FIONBIO, &nonblocking ); 214#else 215 int flags = fcntl( sock, F_GETFL, 0 ); 216 fcntl( sock, F_SETFL, flags & ~O_NONBLOCK ); 217#endif 218 219 m_sock.store( sock, std::memory_order_relaxed ); 220 return true; 221} 222 223bool Socket::ConnectBlocking( const char* addr, uint16_t port ) 224{ 225 assert( !IsValid() ); 226 assert( !m_ptr ); 227 228 struct addrinfo hints; 229 struct addrinfo *res, *ptr; 230 231 memset( &hints, 0, sizeof( hints ) ); 232 hints.ai_family = AF_UNSPEC; 233 hints.ai_socktype = SOCK_STREAM; 234 235 char portbuf[32]; 236 sprintf( portbuf, "%" PRIu16, port ); 237 238 if( getaddrinfo( addr, portbuf, &hints, &res ) != 0 ) return false; 239 int sock = 0; 240 for( ptr = res; ptr; ptr = ptr->ai_next ) 241 { 242 if( ( sock = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ) ) == -1 ) continue; 243#if defined __APPLE__ 244 int val = 1; 245 setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) ); 246#endif 247 if( connect( sock, ptr->ai_addr, ptr->ai_addrlen ) == -1 ) 248 { 249#ifdef _WIN32 250 closesocket( sock ); 251#else 252 close( sock ); 253#endif 254 continue; 255 } 256 break; 257 } 258 freeaddrinfo( res ); 259 if( !ptr ) return false; 260 261 m_sock.store( sock, std::memory_order_relaxed ); 262 return true; 263} 264 265void Socket::Close() 266{ 267 const auto sock = m_sock.load( std::memory_order_relaxed ); 268 assert( sock != -1 ); 269#ifdef _WIN32 270 closesocket( sock ); 271#else 272 close( sock ); 273#endif 274 m_sock.store( -1, std::memory_order_relaxed ); 275} 276 277int Socket::Send( const void* _buf, int len ) 278{ 279 const auto sock = m_sock.load( std::memory_order_relaxed ); 280 auto buf = (const char*)_buf; 281 assert( sock != -1 ); 282 auto start = buf; 283 while( len > 0 ) 284 { 285 auto ret = send( sock, buf, len, MSG_NOSIGNAL ); 286 if( ret == -1 ) return -1; 287 len -= ret; 288 buf += ret; 289 } 290 return int( buf - start ); 291} 292 293int Socket::GetSendBufSize() 294{ 295 const auto sock = m_sock.load( std::memory_order_relaxed ); 296 int bufSize; 297#if defined _WIN32 298 int sz = sizeof( bufSize ); 299 getsockopt( sock, SOL_SOCKET, SO_SNDBUF, (char*)&bufSize, &sz ); 300#else 301 socklen_t sz = sizeof( bufSize ); 302 getsockopt( sock, SOL_SOCKET, SO_SNDBUF, &bufSize, &sz ); 303#endif 304 return bufSize; 305} 306 307int Socket::RecvBuffered( void* buf, int len, int timeout ) 308{ 309 if( len <= m_bufLeft ) 310 { 311 memcpy( buf, m_bufPtr, len ); 312 m_bufPtr += len; 313 m_bufLeft -= len; 314 return len; 315 } 316 317 if( m_bufLeft > 0 ) 318 { 319 memcpy( buf, m_bufPtr, m_bufLeft ); 320 const auto ret = m_bufLeft; 321 m_bufLeft = 0; 322 return ret; 323 } 324 325 if( len >= BufSize ) return Recv( buf, len, timeout ); 326 327 m_bufLeft = Recv( m_buf, BufSize, timeout ); 328 if( m_bufLeft <= 0 ) return m_bufLeft; 329 330 const auto sz = len < m_bufLeft ? len : m_bufLeft; 331 memcpy( buf, m_buf, sz ); 332 m_bufPtr = m_buf + sz; 333 m_bufLeft -= sz; 334 return sz; 335} 336 337int Socket::Recv( void* _buf, int len, int timeout ) 338{ 339 const auto sock = m_sock.load( std::memory_order_relaxed ); 340 auto buf = (char*)_buf; 341 342 struct pollfd fd; 343 fd.fd = (socket_t)sock; 344 fd.events = POLLIN; 345 346 if( poll( &fd, 1, timeout ) > 0 ) 347 { 348 return recv( sock, buf, len, 0 ); 349 } 350 else 351 { 352 return -1; 353 } 354} 355 356int Socket::ReadUpTo( void* _buf, int len, int timeout ) 357{ 358 const auto sock = m_sock.load( std::memory_order_relaxed ); 359 auto buf = (char*)_buf; 360 361 int rd = 0; 362 while( len > 0 ) 363 { 364 const auto res = recv( sock, buf, len, 0 ); 365 if( res == 0 ) break; 366 if( res == -1 ) return -1; 367 len -= res; 368 rd += res; 369 buf += res; 370 } 371 return rd; 372} 373 374bool Socket::Read( void* buf, int len, int timeout ) 375{ 376 auto cbuf = (char*)buf; 377 while( len > 0 ) 378 { 379 if( !ReadImpl( cbuf, len, timeout ) ) return false; 380 } 381 return true; 382} 383 384bool Socket::ReadImpl( char*& buf, int& len, int timeout ) 385{ 386 const auto sz = RecvBuffered( buf, len, timeout ); 387 switch( sz ) 388 { 389 case 0: 390 return false; 391 case -1: 392#ifdef _WIN32 393 { 394 auto err = WSAGetLastError(); 395 if( err == WSAECONNABORTED || err == WSAECONNRESET ) return false; 396 } 397#endif 398 break; 399 default: 400 len -= sz; 401 buf += sz; 402 break; 403 } 404 return true; 405} 406 407bool Socket::ReadRaw( void* _buf, int len, int timeout ) 408{ 409 auto buf = (char*)_buf; 410 while( len > 0 ) 411 { 412 const auto sz = Recv( buf, len, timeout ); 413 if( sz <= 0 ) return false; 414 len -= sz; 415 buf += sz; 416 } 417 return true; 418} 419 420bool Socket::HasData() 421{ 422 const auto sock = m_sock.load( std::memory_order_relaxed ); 423 if( m_bufLeft > 0 ) return true; 424 425 struct pollfd fd; 426 fd.fd = (socket_t)sock; 427 fd.events = POLLIN; 428 429 return poll( &fd, 1, 0 ) > 0; 430} 431 432bool Socket::IsValid() const 433{ 434 return m_sock.load( std::memory_order_relaxed ) >= 0; 435} 436 437 438ListenSocket::ListenSocket() 439 : m_sock( -1 ) 440{ 441#ifdef _WIN32 442 InitWinSock(); 443#endif 444} 445 446ListenSocket::~ListenSocket() 447{ 448 if( m_sock != -1 ) Close(); 449} 450 451static int addrinfo_and_socket_for_family( uint16_t port, int ai_family, struct addrinfo** res ) 452{ 453 struct addrinfo hints; 454 memset( &hints, 0, sizeof( hints ) ); 455 hints.ai_family = ai_family; 456 hints.ai_socktype = SOCK_STREAM; 457#ifndef TRACY_ONLY_LOCALHOST 458 const char* onlyLocalhost = GetEnvVar( "TRACY_ONLY_LOCALHOST" ); 459 if( !onlyLocalhost || onlyLocalhost[0] != '1' ) 460 { 461 hints.ai_flags = AI_PASSIVE; 462 } 463#endif 464 char portbuf[32]; 465 sprintf( portbuf, "%" PRIu16, port ); 466 if( getaddrinfo( nullptr, portbuf, &hints, res ) != 0 ) return -1; 467 int sock = socket( (*res)->ai_family, (*res)->ai_socktype, (*res)->ai_protocol ); 468 if (sock == -1) freeaddrinfo( *res ); 469 return sock; 470} 471 472bool ListenSocket::Listen( uint16_t port, int backlog ) 473{ 474 assert( m_sock == -1 ); 475 476 struct addrinfo* res = nullptr; 477 478#if !defined TRACY_ONLY_IPV4 && !defined TRACY_ONLY_LOCALHOST 479 const char* onlyIPv4 = GetEnvVar( "TRACY_ONLY_IPV4" ); 480 if( !onlyIPv4 || onlyIPv4[0] != '1' ) 481 { 482 m_sock = addrinfo_and_socket_for_family( port, AF_INET6, &res ); 483 } 484#endif 485 if (m_sock == -1) 486 { 487 // IPV6 protocol may not be available/is disabled. Try to create a socket 488 // with the IPV4 protocol 489 m_sock = addrinfo_and_socket_for_family( port, AF_INET, &res ); 490 if( m_sock == -1 ) return false; 491 } 492#if defined _WIN32 493 unsigned long val = 0; 494 setsockopt( m_sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&val, sizeof( val ) ); 495#elif defined BSD 496 int val = 0; 497 setsockopt( m_sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&val, sizeof( val ) ); 498 val = 1; 499 setsockopt( m_sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof( val ) ); 500#else 501 int val = 1; 502 setsockopt( m_sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof( val ) ); 503#endif 504 if( bind( m_sock, res->ai_addr, res->ai_addrlen ) == -1 ) { freeaddrinfo( res ); Close(); return false; } 505 if( listen( m_sock, backlog ) == -1 ) { freeaddrinfo( res ); Close(); return false; } 506 freeaddrinfo( res ); 507 return true; 508} 509 510Socket* ListenSocket::Accept() 511{ 512 struct sockaddr_storage remote; 513 socklen_t sz = sizeof( remote ); 514 515 struct pollfd fd; 516 fd.fd = (socket_t)m_sock; 517 fd.events = POLLIN; 518 519 if( poll( &fd, 1, 10 ) > 0 ) 520 { 521 int sock = accept( m_sock, (sockaddr*)&remote, &sz); 522 if( sock == -1 ) return nullptr; 523 524#if defined __APPLE__ 525 int val = 1; 526 setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) ); 527#endif 528 529 auto ptr = (Socket*)tracy_malloc( sizeof( Socket ) ); 530 new(ptr) Socket( sock ); 531 return ptr; 532 } 533 else 534 { 535 return nullptr; 536 } 537} 538 539void ListenSocket::Close() 540{ 541 assert( m_sock != -1 ); 542#ifdef _WIN32 543 closesocket( m_sock ); 544#else 545 close( m_sock ); 546#endif 547 m_sock = -1; 548} 549 550UdpBroadcast::UdpBroadcast() 551 : m_sock( -1 ) 552{ 553#ifdef _WIN32 554 InitWinSock(); 555#endif 556} 557 558UdpBroadcast::~UdpBroadcast() 559{ 560 if( m_sock != -1 ) Close(); 561} 562 563bool UdpBroadcast::Open( const char* addr, uint16_t port ) 564{ 565 assert( m_sock == -1 ); 566 567 struct addrinfo hints; 568 struct addrinfo *res, *ptr; 569 570 memset( &hints, 0, sizeof( hints ) ); 571 hints.ai_family = AF_INET; 572 hints.ai_socktype = SOCK_DGRAM; 573 574 char portbuf[32]; 575 sprintf( portbuf, "%" PRIu16, port ); 576 577 if( getaddrinfo( addr, portbuf, &hints, &res ) != 0 ) return false; 578 int sock = 0; 579 for( ptr = res; ptr; ptr = ptr->ai_next ) 580 { 581 if( ( sock = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ) ) == -1 ) continue; 582#if defined __APPLE__ 583 int val = 1; 584 setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) ); 585#endif 586#if defined _WIN32 587 unsigned long broadcast = 1; 588 if( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof( broadcast ) ) == -1 ) 589#else 590 int broadcast = 1; 591 if( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof( broadcast ) ) == -1 ) 592#endif 593 { 594#ifdef _WIN32 595 closesocket( sock ); 596#else 597 close( sock ); 598#endif 599 continue; 600 } 601 break; 602 } 603 freeaddrinfo( res ); 604 if( !ptr ) return false; 605 606 m_sock = sock; 607 inet_pton( AF_INET, addr, &m_addr ); 608 return true; 609} 610 611void UdpBroadcast::Close() 612{ 613 assert( m_sock != -1 ); 614#ifdef _WIN32 615 closesocket( m_sock ); 616#else 617 close( m_sock ); 618#endif 619 m_sock = -1; 620} 621 622int UdpBroadcast::Send( uint16_t port, const void* data, int len ) 623{ 624 assert( m_sock != -1 ); 625 struct sockaddr_in addr; 626 addr.sin_family = AF_INET; 627 addr.sin_port = htons( port ); 628 addr.sin_addr.s_addr = m_addr; 629 return sendto( m_sock, (const char*)data, len, MSG_NOSIGNAL, (sockaddr*)&addr, sizeof( addr ) ); 630} 631 632IpAddress::IpAddress() 633 : m_number( 0 ) 634{ 635 *m_text = '\0'; 636} 637 638IpAddress::~IpAddress() 639{ 640} 641 642void IpAddress::Set( const struct sockaddr& addr ) 643{ 644#if defined _WIN32 && ( !defined NTDDI_WIN10 || NTDDI_VERSION < NTDDI_WIN10 ) 645 struct sockaddr_in tmp; 646 memcpy( &tmp, &addr, sizeof( tmp ) ); 647 auto ai = &tmp; 648#else 649 auto ai = (const struct sockaddr_in*)&addr; 650#endif 651 inet_ntop( AF_INET, &ai->sin_addr, m_text, 17 ); 652 m_number = ai->sin_addr.s_addr; 653} 654 655UdpListen::UdpListen() 656 : m_sock( -1 ) 657{ 658#ifdef _WIN32 659 InitWinSock(); 660#endif 661} 662 663UdpListen::~UdpListen() 664{ 665 if( m_sock != -1 ) Close(); 666} 667 668bool UdpListen::Listen( uint16_t port ) 669{ 670 assert( m_sock == -1 ); 671 672 int sock; 673 if( ( sock = socket( AF_INET, SOCK_DGRAM, 0 ) ) == -1 ) return false; 674 675#if defined __APPLE__ 676 int val = 1; 677 setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof( val ) ); 678#endif 679#if defined _WIN32 680 unsigned long reuse = 1; 681 setsockopt( m_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof( reuse ) ); 682#else 683 int reuse = 1; 684 setsockopt( m_sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof( reuse ) ); 685#endif 686#if defined _WIN32 687 unsigned long broadcast = 1; 688 if( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof( broadcast ) ) == -1 ) 689#else 690 int broadcast = 1; 691 if( setsockopt( sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof( broadcast ) ) == -1 ) 692#endif 693 { 694#ifdef _WIN32 695 closesocket( sock ); 696#else 697 close( sock ); 698#endif 699 return false; 700 } 701 702 struct sockaddr_in addr; 703 addr.sin_family = AF_INET; 704 addr.sin_port = htons( port ); 705 addr.sin_addr.s_addr = INADDR_ANY; 706 707 if( bind( sock, (sockaddr*)&addr, sizeof( addr ) ) == -1 ) 708 { 709#ifdef _WIN32 710 closesocket( sock ); 711#else 712 close( sock ); 713#endif 714 return false; 715 } 716 717 m_sock = sock; 718 return true; 719} 720 721void UdpListen::Close() 722{ 723 assert( m_sock != -1 ); 724#ifdef _WIN32 725 closesocket( m_sock ); 726#else 727 close( m_sock ); 728#endif 729 m_sock = -1; 730} 731 732const char* UdpListen::Read( size_t& len, IpAddress& addr, int timeout ) 733{ 734 static char buf[2048]; 735 736 struct pollfd fd; 737 fd.fd = (socket_t)m_sock; 738 fd.events = POLLIN; 739 if( poll( &fd, 1, timeout ) <= 0 ) return nullptr; 740 741 sockaddr sa; 742 socklen_t salen = sizeof( struct sockaddr ); 743 len = (size_t)recvfrom( m_sock, buf, 2048, 0, &sa, &salen ); 744 addr.Set( sa ); 745 746 return buf; 747} 748 749}