The open source OpenXR runtime
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}