2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2022-04-22 23:04:48 +00:00
# include <atomic>
2022-02-14 23:22:52 +00:00
# include <cctype>
# include <cmath>
# include <cstdarg>
# include <cstdio>
# include <cstring>
2022-06-15 19:22:36 +00:00
# include <iterator> // std::size
2007-08-22 07:52:33 +00:00
2008-08-14 17:19:13 +00:00
# include "system.h"
2022-04-22 23:04:48 +00:00
2022-06-03 10:10:05 +00:00
# include "lock_scope.h"
2022-04-22 23:04:48 +00:00
# include "logger.h"
2020-09-26 19:41:58 +00:00
# include <sys/types.h>
2015-08-22 19:07:13 +00:00
2021-06-15 01:31:56 +00:00
# include <chrono>
2021-06-23 05:05:49 +00:00
# include <cinttypes>
2017-03-07 12:03:37 +00:00
# if defined(CONF_WEBSOCKETS)
2021-06-15 01:24:23 +00:00
# include <engine/shared/websockets.h>
2015-02-07 22:15:58 +00:00
# endif
2007-08-22 07:52:33 +00:00
# if defined(CONF_FAMILY_UNIX)
2022-02-14 23:22:52 +00:00
# include <csignal>
2022-06-16 15:23:36 +00:00
# include <sys/stat.h>
2020-09-10 18:14:47 +00:00
# include <sys/time.h>
2022-01-27 01:35:08 +00:00
# include <sys/utsname.h>
2020-09-10 18:14:47 +00:00
# include <sys/wait.h>
# include <unistd.h>
2007-08-22 07:52:33 +00:00
2020-09-10 18:14:47 +00:00
/* unix net includes */
# include <arpa/inet.h>
2022-02-14 23:22:52 +00:00
# include <cerrno>
2020-09-10 18:14:47 +00:00
# include <netdb.h>
# include <netinet/in.h>
# include <pthread.h>
# include <sys/ioctl.h>
# include <sys/socket.h>
2007-08-22 07:52:33 +00:00
2020-09-10 18:14:47 +00:00
# include <dirent.h>
2011-04-13 18:37:12 +00:00
2021-02-12 12:40:29 +00:00
# if defined(CONF_PLATFORM_MACOS)
2020-09-10 18:14:47 +00:00
// some lock and pthread functions are already defined in headers
// included from Carbon.h
// this prevents having duplicate definitions of those
# define _lock_set_user_
# define _task_user_
2015-01-11 02:38:59 +00:00
2020-09-10 18:14:47 +00:00
# include <Carbon/Carbon.h>
2022-01-31 00:54:17 +00:00
# include <mach-o/dyld.h>
2020-09-10 18:14:47 +00:00
# include <mach/mach_time.h>
# endif
2015-07-09 00:08:14 +00:00
2007-08-22 07:52:33 +00:00
# elif defined(CONF_FAMILY_WINDOWS)
2020-09-26 19:41:58 +00:00
# define WIN32_LEAN_AND_MEAN
# undef _WIN32_WINNT
# define _WIN32_WINNT 0x0501 /* required for mingw to get getaddrinfo to work */
# include <windows.h>
# include <winsock2.h>
# include <ws2tcpip.h>
# include <errno.h>
2021-11-28 23:19:46 +00:00
# include <io.h>
2020-09-26 19:41:58 +00:00
# include <process.h>
2021-08-23 13:29:31 +00:00
# include <share.h>
2020-09-26 19:41:58 +00:00
# include <shellapi.h>
# include <wincrypt.h>
2007-08-22 07:52:33 +00:00
# else
2020-09-26 19:41:58 +00:00
# error NOT IMPLEMENTED
2007-08-22 07:52:33 +00:00
# endif
2011-09-08 23:41:53 +00:00
# if defined(CONF_PLATFORM_SOLARIS)
2020-09-26 19:41:58 +00:00
# include <sys/filio.h>
2011-09-08 23:41:53 +00:00
# endif
2007-10-04 09:49:38 +00:00
extern " C " {
2020-09-26 19:41:58 +00:00
IOHANDLE io_stdin ( )
{
return ( IOHANDLE ) stdin ;
}
2008-02-24 16:03:58 +00:00
IOHANDLE io_stdout ( ) { return ( IOHANDLE ) stdout ; }
IOHANDLE io_stderr ( ) { return ( IOHANDLE ) stderr ; }
2022-01-31 00:54:17 +00:00
IOHANDLE io_current_exe ( )
{
// From https://stackoverflow.com/a/1024937.
# if defined(CONF_FAMILY_WINDOWS)
wchar_t wpath [ IO_MAX_PATH_LENGTH ] ;
char path [ IO_MAX_PATH_LENGTH ] ;
2022-03-30 13:16:19 +00:00
if ( ! GetModuleFileNameW ( NULL , wpath , std : : size ( wpath ) ) )
2022-01-31 00:54:17 +00:00
{
return 0 ;
}
if ( ! WideCharToMultiByte ( CP_UTF8 , 0 , wpath , - 1 , path , sizeof ( path ) , NULL , NULL ) )
{
return 0 ;
}
return io_open ( path , IOFLAG_READ ) ;
# elif defined(CONF_PLATFORM_MACOS)
char path [ IO_MAX_PATH_LENGTH ] ;
uint32_t path_size = sizeof ( path ) ;
if ( _NSGetExecutablePath ( path , & path_size ) )
{
return 0 ;
}
return io_open ( path , IOFLAG_READ ) ;
# else
static const char * NAMES [ ] = {
" /proc/self/exe " , // Linux, Android
" /proc/curproc/exe " , // NetBSD
" /proc/curproc/file " , // DragonFly
} ;
for ( auto & name : NAMES )
{
IOHANDLE result = io_open ( name , IOFLAG_READ ) ;
if ( result )
{
return result ;
}
}
return 0 ;
# endif
}
2008-04-05 14:50:43 +00:00
static NETSTATS network_stats = { 0 } ;
2022-03-01 18:13:35 +00:00
# define VLEN 128
# define PACKETSIZE 1400
typedef struct
{
# ifdef CONF_PLATFORM_LINUX
int pos ;
int size ;
struct mmsghdr msgs [ VLEN ] ;
struct iovec iovecs [ VLEN ] ;
char bufs [ VLEN ] [ PACKETSIZE ] ;
char sockaddrs [ VLEN ] [ 128 ] ;
# else
2022-03-01 18:27:48 +00:00
char buf [ PACKETSIZE ] ;
2022-03-01 18:13:35 +00:00
# endif
2022-03-01 18:27:48 +00:00
} NETSOCKET_BUFFER ;
2022-03-01 18:13:35 +00:00
2022-03-01 18:27:48 +00:00
void net_buffer_init ( NETSOCKET_BUFFER * buffer ) ;
void net_buffer_simple ( NETSOCKET_BUFFER * buffer , char * * buf , int * size ) ;
2022-03-01 18:13:35 +00:00
2022-03-01 16:34:42 +00:00
struct NETSOCKET_INTERNAL
{
int type ;
int ipv4sock ;
int ipv6sock ;
int web_ipv4sock ;
2022-03-01 18:13:35 +00:00
2022-03-01 18:27:48 +00:00
NETSOCKET_BUFFER buffer ;
2022-03-01 16:34:42 +00:00
} ;
static NETSOCKET_INTERNAL invalid_socket = { NETTYPE_INVALID , - 1 , - 1 , - 1 } ;
2011-03-28 18:11:28 +00:00
2015-02-07 22:15:58 +00:00
# define AF_WEBSOCKET_INET (0xee)
2022-04-22 23:04:48 +00:00
std : : atomic_bool dbg_assert_failing = false ;
bool dbg_assert_has_failed ( )
2022-03-02 13:28:37 +00:00
{
2022-04-22 23:04:48 +00:00
return dbg_assert_failing . load ( std : : memory_order_acquire ) ;
2022-03-02 13:28:37 +00:00
}
2007-08-22 07:52:33 +00:00
void dbg_assert_imp ( const char * filename , int line , int test , const char * msg )
{
if ( ! test )
{
2022-04-22 23:04:48 +00:00
dbg_assert_failing . store ( true , std : : memory_order_release ) ;
2007-08-22 07:52:33 +00:00
dbg_msg ( " assert " , " %s(%d): %s " , filename , line , msg ) ;
2022-04-22 23:04:48 +00:00
log_global_logger_finish ( ) ;
2021-02-23 19:50:48 +00:00
dbg_break ( ) ;
2007-08-22 07:52:33 +00:00
}
}
2021-02-23 21:15:20 +00:00
void dbg_break ( )
2007-08-22 07:52:33 +00:00
{
2017-10-10 01:33:54 +00:00
# ifdef __GNUC__
__builtin_trap ( ) ;
# else
2021-10-15 10:15:39 +00:00
abort ( ) ;
2017-10-10 01:33:54 +00:00
# endif
2014-09-11 19:38:23 +00:00
}
2007-08-22 07:52:33 +00:00
void dbg_msg ( const char * sys , const char * fmt , . . . )
{
va_list args ;
2017-10-10 01:33:54 +00:00
va_start ( args , fmt ) ;
2022-04-22 23:04:48 +00:00
log_log_v ( LEVEL_INFO , sys , fmt , args ) ;
2017-10-10 01:33:54 +00:00
va_end ( args ) ;
2014-09-09 21:02:05 +00:00
}
2008-03-10 00:48:45 +00:00
/* */
2007-08-22 07:52:33 +00:00
void mem_copy ( void * dest , const void * source , unsigned size )
{
memcpy ( dest , source , size ) ;
}
void mem_move ( void * dest , const void * source , unsigned size )
{
memmove ( dest , source , size ) ;
}
2020-09-26 19:41:58 +00:00
void mem_zero ( void * block , unsigned size )
2007-08-22 07:52:33 +00:00
{
memset ( block , 0 , size ) ;
}
2021-12-17 20:56:31 +00:00
IOHANDLE io_open_impl ( const char * filename , int flags )
2007-08-22 07:52:33 +00:00
{
2021-12-17 20:56:31 +00:00
dbg_assert ( flags = = ( IOFLAG_READ | IOFLAG_SKIP_BOM ) | | flags = = IOFLAG_READ | | flags = = IOFLAG_WRITE | | flags = = IOFLAG_APPEND , " flags must be read, read+skipbom, write or append " ) ;
2021-08-23 10:56:23 +00:00
# if defined(CONF_FAMILY_WINDOWS)
WCHAR wBuffer [ IO_MAX_PATH_LENGTH ] ;
2022-03-30 13:16:19 +00:00
MultiByteToWideChar ( CP_UTF8 , 0 , filename , - 1 , wBuffer , std : : size ( wBuffer ) ) ;
2021-12-17 20:56:31 +00:00
if ( ( flags & IOFLAG_READ ) ! = 0 )
2021-08-23 10:56:23 +00:00
return ( IOHANDLE ) _wfsopen ( wBuffer , L " rb " , _SH_DENYNO ) ;
if ( flags = = IOFLAG_WRITE )
return ( IOHANDLE ) _wfsopen ( wBuffer , L " wb " , _SH_DENYNO ) ;
if ( flags = = IOFLAG_APPEND )
return ( IOHANDLE ) _wfsopen ( wBuffer , L " ab " , _SH_DENYNO ) ;
return 0x0 ;
# else
2021-12-17 20:56:31 +00:00
if ( ( flags & IOFLAG_READ ) ! = 0 )
2007-08-22 07:52:33 +00:00
return ( IOHANDLE ) fopen ( filename , " rb " ) ;
if ( flags = = IOFLAG_WRITE )
return ( IOHANDLE ) fopen ( filename , " wb " ) ;
2015-12-19 17:12:45 +00:00
if ( flags = = IOFLAG_APPEND )
return ( IOHANDLE ) fopen ( filename , " ab " ) ;
2007-08-22 07:52:33 +00:00
return 0x0 ;
2021-08-23 10:56:23 +00:00
# endif
2007-08-22 07:52:33 +00:00
}
2021-12-17 20:56:31 +00:00
IOHANDLE io_open ( const char * filename , int flags )
{
IOHANDLE result = io_open_impl ( filename , flags ) ;
unsigned char buf [ 3 ] ;
if ( ( flags & IOFLAG_SKIP_BOM ) = = 0 | | ! result )
{
return result ;
}
if ( io_read ( result , buf , sizeof ( buf ) ) ! = 3 | | buf [ 0 ] ! = 0xef | | buf [ 1 ] ! = 0xbb | | buf [ 2 ] ! = 0xbf )
{
io_seek ( result , 0 , IOSEEK_START ) ;
}
return result ;
}
2007-08-22 07:52:33 +00:00
unsigned io_read ( IOHANDLE io , void * buffer , unsigned size )
{
2020-09-26 19:41:58 +00:00
return fread ( buffer , 1 , size , ( FILE * ) io ) ;
2007-08-22 07:52:33 +00:00
}
2022-06-14 18:03:22 +00:00
void io_read_all ( IOHANDLE io , void * * result , unsigned * result_len )
{
long signed_len = io_length ( io ) ;
unsigned len = signed_len < 0 ? 1024 : ( unsigned ) signed_len ; // use default initial size if we couldn't get the length
char * buffer = ( char * ) malloc ( len + 1 ) ;
unsigned read = io_read ( io , buffer , len + 1 ) ; // +1 to check if the file size is larger than expected
if ( read < len )
{
buffer = ( char * ) realloc ( buffer , read + 1 ) ;
len = read ;
}
else if ( read > len )
{
unsigned cap = 2 * read ;
len = read ;
buffer = ( char * ) realloc ( buffer , cap ) ;
while ( ( read = io_read ( io , buffer + len , cap - len ) ) ! = 0 )
{
len + = read ;
if ( len = = cap )
{
cap * = 2 ;
buffer = ( char * ) realloc ( buffer , cap ) ;
}
}
buffer = ( char * ) realloc ( buffer , len + 1 ) ;
}
buffer [ len ] = 0 ;
* result = buffer ;
* result_len = len ;
}
char * io_read_all_str ( IOHANDLE io )
{
void * buffer ;
unsigned len ;
io_read_all ( io , & buffer , & len ) ;
if ( mem_has_null ( buffer , len ) )
{
free ( buffer ) ;
return nullptr ;
}
return ( char * ) buffer ;
}
2010-09-03 19:17:32 +00:00
unsigned io_skip ( IOHANDLE io , int size )
2007-08-22 07:52:33 +00:00
{
2020-09-26 19:41:58 +00:00
fseek ( ( FILE * ) io , size , SEEK_CUR ) ;
2007-08-22 07:52:33 +00:00
return size ;
}
int io_seek ( IOHANDLE io , int offset , int origin )
{
int real_origin ;
switch ( origin )
{
2007-08-25 08:48:24 +00:00
case IOSEEK_START :
2007-08-22 07:52:33 +00:00
real_origin = SEEK_SET ;
break ;
2007-08-25 08:48:24 +00:00
case IOSEEK_CUR :
2007-08-22 07:52:33 +00:00
real_origin = SEEK_CUR ;
break ;
2007-08-25 08:48:24 +00:00
case IOSEEK_END :
2007-08-22 07:52:33 +00:00
real_origin = SEEK_END ;
2011-05-04 23:43:27 +00:00
break ;
default :
return - 1 ;
2007-08-22 07:52:33 +00:00
}
2020-09-26 19:41:58 +00:00
return fseek ( ( FILE * ) io , offset , real_origin ) ;
2007-08-22 07:52:33 +00:00
}
long int io_tell ( IOHANDLE io )
{
2020-09-26 19:41:58 +00:00
return ftell ( ( FILE * ) io ) ;
2007-08-22 07:52:33 +00:00
}
long int io_length ( IOHANDLE io )
{
long int length ;
io_seek ( io , 0 , IOSEEK_END ) ;
length = io_tell ( io ) ;
2007-08-25 08:48:24 +00:00
io_seek ( io , 0 , IOSEEK_START ) ;
2007-08-22 07:52:33 +00:00
return length ;
}
2017-10-10 01:33:54 +00:00
int io_error ( IOHANDLE io )
{
2020-09-26 19:41:58 +00:00
return ferror ( ( FILE * ) io ) ;
2017-10-10 01:33:54 +00:00
}
2007-08-22 07:52:33 +00:00
unsigned io_write ( IOHANDLE io , const void * buffer , unsigned size )
{
2020-09-26 19:41:58 +00:00
return fwrite ( buffer , 1 , size , ( FILE * ) io ) ;
2007-08-22 07:52:33 +00:00
}
2011-12-29 22:36:53 +00:00
unsigned io_write_newline ( IOHANDLE io )
{
# if defined(CONF_FAMILY_WINDOWS)
2020-09-26 19:41:58 +00:00
return fwrite ( " \r \n " , 1 , 2 , ( FILE * ) io ) ;
2011-12-29 22:36:53 +00:00
# else
2020-09-26 19:41:58 +00:00
return fwrite ( " \n " , 1 , 1 , ( FILE * ) io ) ;
2011-12-29 22:36:53 +00:00
# endif
}
2007-08-22 07:52:33 +00:00
int io_close ( IOHANDLE io )
{
2020-09-26 19:41:58 +00:00
return fclose ( ( FILE * ) io ) ! = 0 ;
2007-08-22 07:52:33 +00:00
}
2008-03-10 00:48:45 +00:00
int io_flush ( IOHANDLE io )
{
2020-09-26 19:41:58 +00:00
return fflush ( ( FILE * ) io ) ;
2008-03-10 00:48:45 +00:00
}
2022-01-31 21:07:51 +00:00
int io_sync ( IOHANDLE io )
2021-11-28 23:19:46 +00:00
{
2022-01-31 21:07:51 +00:00
if ( io_flush ( io ) )
{
return 1 ;
}
2021-11-28 23:19:46 +00:00
# if defined(CONF_FAMILY_WINDOWS)
2022-01-31 21:07:51 +00:00
return FlushFileBuffers ( ( HANDLE ) _get_osfhandle ( _fileno ( ( FILE * ) io ) ) ) = = 0 ;
2021-11-28 23:19:46 +00:00
# else
2022-01-31 21:07:51 +00:00
return fsync ( fileno ( ( FILE * ) io ) ) ! = 0 ;
2021-11-28 23:19:46 +00:00
# endif
}
2017-10-10 01:33:54 +00:00
# define ASYNC_BUFSIZE 8 * 1024
2018-01-13 18:17:33 +00:00
# define ASYNC_LOCAL_BUFSIZE 64 * 1024
2017-10-10 01:33:54 +00:00
2020-12-02 18:11:19 +00:00
// TODO: Use Thread Safety Analysis when this file is converted to C++
2017-10-20 09:24:45 +00:00
struct ASYNCIO
2017-10-10 01:33:54 +00:00
{
LOCK lock ;
IOHANDLE io ;
SEMAPHORE sphore ;
void * thread ;
unsigned char * buffer ;
unsigned int buffer_size ;
unsigned int read_pos ;
unsigned int write_pos ;
int error ;
unsigned char finish ;
unsigned char refcount ;
2017-10-20 09:24:45 +00:00
} ;
2017-10-10 01:33:54 +00:00
enum
{
ASYNCIO_RUNNING ,
ASYNCIO_CLOSE ,
ASYNCIO_EXIT ,
} ;
struct BUFFERS
{
unsigned char * buf1 ;
unsigned int len1 ;
unsigned char * buf2 ;
unsigned int len2 ;
} ;
static void buffer_ptrs ( ASYNCIO * aio , struct BUFFERS * buffers )
{
mem_zero ( buffers , sizeof ( * buffers ) ) ;
if ( aio - > read_pos < aio - > write_pos )
{
buffers - > buf1 = aio - > buffer + aio - > read_pos ;
buffers - > len1 = aio - > write_pos - aio - > read_pos ;
}
else if ( aio - > read_pos > aio - > write_pos )
{
buffers - > buf1 = aio - > buffer + aio - > read_pos ;
buffers - > len1 = aio - > buffer_size - aio - > read_pos ;
buffers - > buf2 = aio - > buffer ;
buffers - > len2 = aio - > write_pos ;
}
}
2020-12-02 18:11:19 +00:00
static void aio_handle_free_and_unlock ( ASYNCIO * aio ) RELEASE ( aio - > lock )
2017-10-10 01:33:54 +00:00
{
int do_free ;
aio - > refcount - - ;
do_free = aio - > refcount = = 0 ;
lock_unlock ( aio - > lock ) ;
if ( do_free )
{
2018-04-09 09:56:39 +00:00
free ( aio - > buffer ) ;
2017-10-10 01:33:54 +00:00
sphore_destroy ( & aio - > sphore ) ;
lock_destroy ( aio - > lock ) ;
2018-04-09 09:56:39 +00:00
free ( aio ) ;
2017-10-10 01:33:54 +00:00
}
}
2017-10-13 00:48:42 +00:00
static void aio_thread ( void * user )
2017-10-10 01:33:54 +00:00
{
2021-06-15 01:24:23 +00:00
ASYNCIO * aio = ( ASYNCIO * ) user ;
2017-10-10 01:33:54 +00:00
lock_wait ( aio - > lock ) ;
2022-02-14 23:12:52 +00:00
while ( true )
2017-10-10 01:33:54 +00:00
{
struct BUFFERS buffers ;
int result_io_error ;
2018-01-13 18:17:33 +00:00
unsigned char local_buffer [ ASYNC_LOCAL_BUFSIZE ] ;
unsigned int local_buffer_len = 0 ;
2017-10-10 01:33:54 +00:00
if ( aio - > read_pos = = aio - > write_pos )
{
if ( aio - > finish ! = ASYNCIO_RUNNING )
{
if ( aio - > finish = = ASYNCIO_CLOSE )
{
io_close ( aio - > io ) ;
}
2017-10-13 00:48:42 +00:00
aio_handle_free_and_unlock ( aio ) ;
2017-10-10 01:33:54 +00:00
break ;
}
lock_unlock ( aio - > lock ) ;
sphore_wait ( & aio - > sphore ) ;
lock_wait ( aio - > lock ) ;
continue ;
}
buffer_ptrs ( aio , & buffers ) ;
2018-01-13 18:17:33 +00:00
if ( buffers . buf1 )
2017-10-10 01:33:54 +00:00
{
2018-01-13 18:17:33 +00:00
if ( buffers . len1 > sizeof ( local_buffer ) - local_buffer_len )
{
buffers . len1 = sizeof ( local_buffer ) - local_buffer_len ;
}
mem_copy ( local_buffer + local_buffer_len , buffers . buf1 , buffers . len1 ) ;
local_buffer_len + = buffers . len1 ;
if ( buffers . buf2 )
{
if ( buffers . len2 > sizeof ( local_buffer ) - local_buffer_len )
{
buffers . len2 = sizeof ( local_buffer ) - local_buffer_len ;
}
mem_copy ( local_buffer + local_buffer_len , buffers . buf2 , buffers . len2 ) ;
local_buffer_len + = buffers . len2 ;
}
2017-10-10 01:33:54 +00:00
}
2018-01-13 18:17:33 +00:00
aio - > read_pos = ( aio - > read_pos + buffers . len1 + buffers . len2 ) % aio - > buffer_size ;
lock_unlock ( aio - > lock ) ;
io_write ( aio - > io , local_buffer , local_buffer_len ) ;
2017-10-10 01:33:54 +00:00
io_flush ( aio - > io ) ;
result_io_error = io_error ( aio - > io ) ;
lock_wait ( aio - > lock ) ;
aio - > error = result_io_error ;
}
}
2017-10-13 00:48:42 +00:00
ASYNCIO * aio_new ( IOHANDLE io )
2017-10-10 01:33:54 +00:00
{
2021-06-15 01:24:23 +00:00
ASYNCIO * aio = ( ASYNCIO * ) malloc ( sizeof ( * aio ) ) ;
2017-10-10 01:33:54 +00:00
if ( ! aio )
{
return 0 ;
}
aio - > io = io ;
aio - > lock = lock_create ( ) ;
sphore_init ( & aio - > sphore ) ;
aio - > thread = 0 ;
2021-06-15 01:24:23 +00:00
aio - > buffer = ( unsigned char * ) malloc ( ASYNC_BUFSIZE ) ;
2017-10-10 01:33:54 +00:00
if ( ! aio - > buffer )
{
sphore_destroy ( & aio - > sphore ) ;
lock_destroy ( aio - > lock ) ;
2018-04-09 09:56:39 +00:00
free ( aio ) ;
2017-10-10 01:33:54 +00:00
return 0 ;
}
aio - > buffer_size = ASYNC_BUFSIZE ;
aio - > read_pos = 0 ;
aio - > write_pos = 0 ;
aio - > error = 0 ;
aio - > finish = ASYNCIO_RUNNING ;
aio - > refcount = 2 ;
2019-03-19 10:44:16 +00:00
aio - > thread = thread_init ( aio_thread , aio , " aio " ) ;
2017-10-10 01:33:54 +00:00
if ( ! aio - > thread )
{
2018-04-09 09:56:39 +00:00
free ( aio - > buffer ) ;
2017-10-10 01:33:54 +00:00
sphore_destroy ( & aio - > sphore ) ;
lock_destroy ( aio - > lock ) ;
2018-04-09 09:56:39 +00:00
free ( aio ) ;
2017-10-10 01:33:54 +00:00
return 0 ;
}
return aio ;
}
static unsigned int buffer_len ( ASYNCIO * aio )
{
if ( aio - > write_pos > = aio - > read_pos )
{
return aio - > write_pos - aio - > read_pos ;
}
else
{
return aio - > buffer_size + aio - > write_pos - aio - > read_pos ;
}
}
static unsigned int next_buffer_size ( unsigned int cur_size , unsigned int need_size )
{
while ( cur_size < need_size )
{
cur_size * = 2 ;
}
return cur_size ;
}
2020-12-02 18:11:19 +00:00
void aio_lock ( ASYNCIO * aio ) ACQUIRE ( aio - > lock )
2017-10-10 01:33:54 +00:00
{
lock_wait ( aio - > lock ) ;
2017-11-26 16:01:11 +00:00
}
2020-12-02 18:11:19 +00:00
void aio_unlock ( ASYNCIO * aio ) RELEASE ( aio - > lock )
2017-11-26 16:01:11 +00:00
{
lock_unlock ( aio - > lock ) ;
sphore_signal ( & aio - > sphore ) ;
}
void aio_write_unlocked ( ASYNCIO * aio , const void * buffer , unsigned size )
{
unsigned int remaining ;
2017-10-10 01:33:54 +00:00
remaining = aio - > buffer_size - buffer_len ( aio ) ;
// Don't allow full queue to distinguish between empty and full queue.
if ( size < remaining )
{
unsigned int remaining_contiguous = aio - > buffer_size - aio - > write_pos ;
if ( size > remaining_contiguous )
{
mem_copy ( aio - > buffer + aio - > write_pos , buffer , remaining_contiguous ) ;
size - = remaining_contiguous ;
buffer = ( ( unsigned char * ) buffer ) + remaining_contiguous ;
aio - > write_pos = 0 ;
}
mem_copy ( aio - > buffer + aio - > write_pos , buffer , size ) ;
aio - > write_pos = ( aio - > write_pos + size ) % aio - > buffer_size ;
}
else
{
// Add 1 so the new buffer isn't completely filled.
unsigned int new_written = buffer_len ( aio ) + size + 1 ;
unsigned int next_size = next_buffer_size ( aio - > buffer_size , new_written ) ;
unsigned int next_len = 0 ;
2021-06-15 01:24:23 +00:00
unsigned char * next_buffer = ( unsigned char * ) malloc ( next_size ) ;
2017-10-10 01:33:54 +00:00
struct BUFFERS buffers ;
buffer_ptrs ( aio , & buffers ) ;
if ( buffers . buf1 )
{
mem_copy ( next_buffer + next_len , buffers . buf1 , buffers . len1 ) ;
next_len + = buffers . len1 ;
if ( buffers . buf2 )
{
mem_copy ( next_buffer + next_len , buffers . buf2 , buffers . len2 ) ;
next_len + = buffers . len2 ;
}
}
mem_copy ( next_buffer + next_len , buffer , size ) ;
next_len + = size ;
2018-04-09 09:56:39 +00:00
free ( aio - > buffer ) ;
2017-10-10 01:33:54 +00:00
aio - > buffer = next_buffer ;
aio - > buffer_size = next_size ;
aio - > read_pos = 0 ;
aio - > write_pos = next_len ;
}
}
2017-11-26 16:01:11 +00:00
void aio_write ( ASYNCIO * aio , const void * buffer , unsigned size )
{
aio_lock ( aio ) ;
aio_write_unlocked ( aio , buffer , size ) ;
aio_unlock ( aio ) ;
}
void aio_write_newline_unlocked ( ASYNCIO * aio )
2017-10-10 01:33:54 +00:00
{
# if defined(CONF_FAMILY_WINDOWS)
2017-11-26 16:01:11 +00:00
aio_write_unlocked ( aio , " \r \n " , 2 ) ;
2017-10-10 01:33:54 +00:00
# else
2017-11-26 16:01:11 +00:00
aio_write_unlocked ( aio , " \n " , 1 ) ;
2017-10-10 01:33:54 +00:00
# endif
}
2017-11-26 16:01:11 +00:00
void aio_write_newline ( ASYNCIO * aio )
{
aio_lock ( aio ) ;
aio_write_newline_unlocked ( aio ) ;
aio_unlock ( aio ) ;
}
2017-10-13 00:48:42 +00:00
int aio_error ( ASYNCIO * aio )
2017-10-10 01:33:54 +00:00
{
2022-06-03 10:10:05 +00:00
CLockScope ls ( aio - > lock ) ;
return aio - > error ;
2017-10-10 01:33:54 +00:00
}
2017-10-13 00:48:42 +00:00
void aio_free ( ASYNCIO * aio )
2017-10-10 01:33:54 +00:00
{
lock_wait ( aio - > lock ) ;
if ( aio - > thread )
{
thread_detach ( aio - > thread ) ;
aio - > thread = 0 ;
}
2017-10-13 00:48:42 +00:00
aio_handle_free_and_unlock ( aio ) ;
2017-10-10 01:33:54 +00:00
}
2017-10-13 00:48:42 +00:00
void aio_close ( ASYNCIO * aio )
2017-10-10 01:33:54 +00:00
{
2022-06-03 10:10:05 +00:00
{
CLockScope ls ( aio - > lock ) ;
aio - > finish = ASYNCIO_CLOSE ;
}
2017-10-10 01:33:54 +00:00
sphore_signal ( & aio - > sphore ) ;
}
2017-10-13 00:48:42 +00:00
void aio_wait ( ASYNCIO * aio )
2017-10-10 01:33:54 +00:00
{
void * thread ;
2017-10-11 22:53:12 +00:00
{
2022-06-03 10:10:05 +00:00
CLockScope ls ( aio - > lock ) ;
thread = aio - > thread ;
aio - > thread = 0 ;
if ( aio - > finish = = ASYNCIO_RUNNING )
{
aio - > finish = ASYNCIO_EXIT ;
}
2017-10-11 22:53:12 +00:00
}
2017-10-10 01:33:54 +00:00
sphore_signal ( & aio - > sphore ) ;
thread_wait ( thread ) ;
}
2018-06-20 20:26:43 +00:00
struct THREAD_RUN
{
void ( * threadfunc ) ( void * ) ;
void * u ;
} ;
# if defined(CONF_FAMILY_UNIX)
static void * thread_run ( void * user )
# elif defined(CONF_FAMILY_WINDOWS)
2018-10-01 17:23:33 +00:00
static unsigned long __stdcall thread_run ( void * user )
2018-06-20 20:26:43 +00:00
# else
# error not implemented
# endif
{
2021-06-15 01:24:23 +00:00
struct THREAD_RUN * data = ( THREAD_RUN * ) user ;
2018-06-20 20:26:43 +00:00
void ( * threadfunc ) ( void * ) = data - > threadfunc ;
void * u = data - > u ;
free ( data ) ;
threadfunc ( u ) ;
return 0 ;
}
2019-03-19 10:44:16 +00:00
void * thread_init ( void ( * threadfunc ) ( void * ) , void * u , const char * name )
2008-02-10 21:54:52 +00:00
{
2021-06-15 01:24:23 +00:00
struct THREAD_RUN * data = ( THREAD_RUN * ) malloc ( sizeof ( * data ) ) ;
2018-06-20 20:26:43 +00:00
data - > threadfunc = threadfunc ;
data - > u = u ;
2008-02-10 21:54:52 +00:00
# if defined(CONF_FAMILY_UNIX)
2017-10-09 22:08:24 +00:00
{
2018-06-20 20:26:43 +00:00
pthread_t id ;
2022-01-21 22:50:17 +00:00
pthread_attr_t attr ;
pthread_attr_init ( & attr ) ;
# if defined(CONF_PLATFORM_MACOS)
pthread_attr_set_qos_class_np ( & attr , QOS_CLASS_USER_INTERACTIVE , 0 ) ;
# endif
int result = pthread_create ( & id , & attr , thread_run , data ) ;
2019-03-19 10:44:16 +00:00
if ( result ! = 0 )
2018-06-20 20:26:43 +00:00
{
2019-03-19 10:44:16 +00:00
dbg_msg ( " thread " , " creating %s thread failed: %d " , name , result ) ;
2018-06-20 20:26:43 +00:00
return 0 ;
}
2020-09-26 19:41:58 +00:00
return ( void * ) id ;
2017-10-09 22:08:24 +00:00
}
2008-02-10 21:54:52 +00:00
# elif defined(CONF_FAMILY_WINDOWS)
2018-06-20 20:26:43 +00:00
return CreateThread ( NULL , 0 , thread_run , data , 0 , NULL ) ;
2008-02-10 21:54:52 +00:00
# else
2020-09-26 19:41:58 +00:00
# error not implemented
2008-02-10 21:54:52 +00:00
# endif
}
void thread_wait ( void * thread )
{
# if defined(CONF_FAMILY_UNIX)
2017-08-31 17:13:55 +00:00
int result = pthread_join ( ( pthread_t ) thread , NULL ) ;
if ( result ! = 0 )
dbg_msg ( " thread " , " !! %d " , result ) ;
2008-02-10 21:54:52 +00:00
# elif defined(CONF_FAMILY_WINDOWS)
WaitForSingleObject ( ( HANDLE ) thread , INFINITE ) ;
2017-10-09 22:08:24 +00:00
CloseHandle ( thread ) ;
2008-02-10 21:54:52 +00:00
# else
2020-09-26 19:41:58 +00:00
# error not implemented
2008-02-10 21:54:52 +00:00
# endif
}
2021-06-15 02:15:24 +00:00
void thread_yield ( )
2008-02-10 21:54:52 +00:00
{
# if defined(CONF_FAMILY_UNIX)
2019-03-19 10:44:16 +00:00
int result = sched_yield ( ) ;
if ( result ! = 0 )
dbg_msg ( " thread " , " yield failed: %d " , errno ) ;
2008-02-10 21:54:52 +00:00
# elif defined(CONF_FAMILY_WINDOWS)
Sleep ( 0 ) ;
# else
2020-09-26 19:41:58 +00:00
# error not implemented
2008-02-10 21:54:52 +00:00
# endif
}
2011-05-01 13:48:09 +00:00
void thread_detach ( void * thread )
{
# if defined(CONF_FAMILY_UNIX)
2019-03-19 10:44:16 +00:00
int result = pthread_detach ( ( pthread_t ) ( thread ) ) ;
if ( result ! = 0 )
dbg_msg ( " thread " , " detach failed: %d " , result ) ;
2011-05-01 13:48:09 +00:00
# elif defined(CONF_FAMILY_WINDOWS)
CloseHandle ( thread ) ;
# else
2020-09-26 19:41:58 +00:00
# error not implemented
2011-05-01 13:48:09 +00:00
# endif
}
2019-03-19 10:44:16 +00:00
void * thread_init_and_detach ( void ( * threadfunc ) ( void * ) , void * u , const char * name )
{
void * thread = thread_init ( threadfunc , u , name ) ;
if ( thread )
thread_detach ( thread ) ;
return thread ;
}
2008-02-10 21:54:52 +00:00
2007-10-02 16:19:25 +00:00
# if defined(CONF_FAMILY_UNIX)
typedef pthread_mutex_t LOCKINTERNAL ;
2007-10-04 09:49:38 +00:00
# elif defined(CONF_FAMILY_WINDOWS)
typedef CRITICAL_SECTION LOCKINTERNAL ;
2007-10-02 16:19:25 +00:00
# else
2020-09-26 19:41:58 +00:00
# error not implemented on this platform
2007-10-02 16:19:25 +00:00
# endif
2021-06-15 02:15:24 +00:00
LOCK lock_create ( )
2007-10-02 16:19:25 +00:00
{
2018-04-09 09:56:39 +00:00
LOCKINTERNAL * lock = ( LOCKINTERNAL * ) malloc ( sizeof ( * lock ) ) ;
2019-03-19 10:44:16 +00:00
# if defined(CONF_FAMILY_UNIX)
int result ;
# endif
if ( ! lock )
return 0 ;
2007-10-02 16:19:25 +00:00
# if defined(CONF_FAMILY_UNIX)
2019-03-19 10:44:16 +00:00
result = pthread_mutex_init ( lock , 0x0 ) ;
if ( result ! = 0 )
{
dbg_msg ( " lock " , " init failed: %d " , result ) ;
2020-10-12 13:19:51 +00:00
free ( lock ) ;
2019-03-19 10:44:16 +00:00
return 0 ;
}
2007-10-04 09:49:38 +00:00
# elif defined(CONF_FAMILY_WINDOWS)
InitializeCriticalSection ( ( LPCRITICAL_SECTION ) lock ) ;
2007-10-02 16:19:25 +00:00
# else
2020-09-26 19:41:58 +00:00
# error not implemented on this platform
2007-10-02 16:19:25 +00:00
# endif
2007-10-06 17:01:06 +00:00
return ( LOCK ) lock ;
2007-10-02 16:19:25 +00:00
}
void lock_destroy ( LOCK lock )
{
# if defined(CONF_FAMILY_UNIX)
2019-03-19 10:44:16 +00:00
int result = pthread_mutex_destroy ( ( LOCKINTERNAL * ) lock ) ;
if ( result ! = 0 )
dbg_msg ( " lock " , " destroy failed: %d " , result ) ;
2007-10-04 09:49:38 +00:00
# elif defined(CONF_FAMILY_WINDOWS)
DeleteCriticalSection ( ( LPCRITICAL_SECTION ) lock ) ;
2007-10-02 16:19:25 +00:00
# else
2020-09-26 19:41:58 +00:00
# error not implemented on this platform
2007-10-02 16:19:25 +00:00
# endif
2018-04-09 09:56:39 +00:00
free ( lock ) ;
2007-10-02 16:19:25 +00:00
}
2015-04-07 17:07:38 +00:00
int lock_trylock ( LOCK lock )
2007-10-02 16:19:25 +00:00
{
# if defined(CONF_FAMILY_UNIX)
2007-10-06 17:01:06 +00:00
return pthread_mutex_trylock ( ( LOCKINTERNAL * ) lock ) ;
2007-10-04 09:49:38 +00:00
# elif defined(CONF_FAMILY_WINDOWS)
2012-07-19 08:01:57 +00:00
return ! TryEnterCriticalSection ( ( LPCRITICAL_SECTION ) lock ) ;
2007-10-02 16:19:25 +00:00
# else
2020-09-26 19:41:58 +00:00
# error not implemented on this platform
2007-10-02 16:19:25 +00:00
# endif
}
2020-12-02 18:11:19 +00:00
# ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wthread-safety-analysis"
# endif
2007-10-02 16:19:25 +00:00
void lock_wait ( LOCK lock )
{
# if defined(CONF_FAMILY_UNIX)
2019-03-19 10:44:16 +00:00
int result = pthread_mutex_lock ( ( LOCKINTERNAL * ) lock ) ;
if ( result ! = 0 )
dbg_msg ( " lock " , " lock failed: %d " , result ) ;
2007-10-04 09:49:38 +00:00
# elif defined(CONF_FAMILY_WINDOWS)
EnterCriticalSection ( ( LPCRITICAL_SECTION ) lock ) ;
2007-10-02 16:19:25 +00:00
# else
2020-09-26 19:41:58 +00:00
# error not implemented on this platform
2007-10-02 16:19:25 +00:00
# endif
}
2015-04-07 17:07:38 +00:00
void lock_unlock ( LOCK lock )
2007-10-02 16:19:25 +00:00
{
# if defined(CONF_FAMILY_UNIX)
2019-03-19 10:44:16 +00:00
int result = pthread_mutex_unlock ( ( LOCKINTERNAL * ) lock ) ;
if ( result ! = 0 )
dbg_msg ( " lock " , " unlock failed: %d " , result ) ;
2007-10-04 09:49:38 +00:00
# elif defined(CONF_FAMILY_WINDOWS)
LeaveCriticalSection ( ( LPCRITICAL_SECTION ) lock ) ;
2007-10-02 16:19:25 +00:00
# else
2020-09-26 19:41:58 +00:00
# error not implemented on this platform
2007-10-02 16:19:25 +00:00
# endif
}
2020-12-02 18:11:19 +00:00
# ifdef __clang__
# pragma clang diagnostic pop
# endif
2007-10-02 16:19:25 +00:00
2017-08-31 17:13:55 +00:00
# if defined(CONF_FAMILY_WINDOWS)
2020-09-26 19:41:58 +00:00
void sphore_init ( SEMAPHORE * sem )
{
* sem = CreateSemaphore ( 0 , 0 , 10000 , 0 ) ;
}
2017-08-31 10:30:42 +00:00
void sphore_wait ( SEMAPHORE * sem ) { WaitForSingleObject ( ( HANDLE ) * sem , INFINITE ) ; }
void sphore_signal ( SEMAPHORE * sem ) { ReleaseSemaphore ( ( HANDLE ) * sem , 1 , NULL ) ; }
void sphore_destroy ( SEMAPHORE * sem ) { CloseHandle ( ( HANDLE ) * sem ) ; }
2021-02-12 12:40:29 +00:00
# elif defined(CONF_PLATFORM_MACOS)
2017-08-31 10:30:42 +00:00
void sphore_init ( SEMAPHORE * sem )
2017-08-31 08:59:12 +00:00
{
2017-08-31 09:29:49 +00:00
char aBuf [ 64 ] ;
2017-10-09 22:08:24 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " /%d-ddnet.tw-%p " , pid ( ) , ( void * ) sem ) ;
2017-08-31 09:29:49 +00:00
* sem = sem_open ( aBuf , O_CREAT | O_EXCL , S_IRWXU | S_IRWXG , 0 ) ;
2017-08-31 08:59:12 +00:00
}
2017-08-31 10:30:42 +00:00
void sphore_wait ( SEMAPHORE * sem ) { sem_wait ( * sem ) ; }
void sphore_signal ( SEMAPHORE * sem ) { sem_post ( * sem ) ; }
2017-08-31 17:13:55 +00:00
void sphore_destroy ( SEMAPHORE * sem )
{
char aBuf [ 64 ] ;
sem_close ( * sem ) ;
2017-10-09 22:08:24 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " /%d-ddnet.tw-%p " , pid ( ) , ( void * ) sem ) ;
2017-08-31 17:13:55 +00:00
sem_unlink ( aBuf ) ;
}
# elif defined(CONF_FAMILY_UNIX)
2019-03-19 10:44:16 +00:00
void sphore_init ( SEMAPHORE * sem )
{
if ( sem_init ( sem , 0 , 0 ) ! = 0 )
dbg_msg ( " sphore " , " init failed: %d " , errno ) ;
}
void sphore_wait ( SEMAPHORE * sem )
{
if ( sem_wait ( sem ) ! = 0 )
dbg_msg ( " sphore " , " wait failed: %d " , errno ) ;
}
void sphore_signal ( SEMAPHORE * sem )
{
if ( sem_post ( sem ) ! = 0 )
dbg_msg ( " sphore " , " post failed: %d " , errno ) ;
}
void sphore_destroy ( SEMAPHORE * sem )
{
if ( sem_destroy ( sem ) ! = 0 )
dbg_msg ( " sphore " , " destroy failed: %d " , errno ) ;
}
2012-01-01 14:56:28 +00:00
# endif
2014-11-18 17:21:30 +00:00
static int new_tick = - 1 ;
2014-11-09 23:08:50 +00:00
2021-06-15 02:15:24 +00:00
void set_new_tick ( )
2014-11-09 23:08:50 +00:00
{
new_tick = 1 ;
}
2012-01-01 14:56:28 +00:00
2007-08-22 07:52:33 +00:00
/* ----- time ----- */
2021-06-15 01:31:56 +00:00
static_assert ( std : : chrono : : steady_clock : : is_steady , " Compiler does not support steady clocks, it might be out of date. " ) ;
2022-05-18 16:00:05 +00:00
static_assert ( std : : chrono : : steady_clock : : period : : den / std : : chrono : : steady_clock : : period : : num > = 1000000000 , " Compiler has a bad timer precision and might be out of date. " ) ;
2021-06-15 01:31:56 +00:00
static const std : : chrono : : time_point < std : : chrono : : steady_clock > tw_start_time = std : : chrono : : steady_clock : : now ( ) ;
2021-06-15 02:15:24 +00:00
int64_t time_get_impl ( )
2007-08-22 07:52:33 +00:00
{
2022-05-18 16:00:05 +00:00
return std : : chrono : : duration_cast < std : : chrono : : nanoseconds > ( std : : chrono : : steady_clock : : now ( ) - tw_start_time ) . count ( ) ;
2007-08-22 07:52:33 +00:00
}
2021-06-15 02:15:24 +00:00
int64_t time_get ( )
2018-03-12 15:12:06 +00:00
{
2021-06-23 05:05:49 +00:00
static int64_t last = 0 ;
2018-03-12 15:12:06 +00:00
if ( new_tick = = 0 )
return last ;
if ( new_tick ! = - 1 )
new_tick = 0 ;
last = time_get_impl ( ) ;
2018-03-12 15:21:21 +00:00
return last ;
2018-03-12 15:12:06 +00:00
}
2021-06-15 02:15:24 +00:00
int64_t time_freq ( )
2007-08-22 07:52:33 +00:00
{
2022-05-18 16:00:05 +00:00
using namespace std : : chrono_literals ;
return std : : chrono : : nanoseconds ( 1 s ) . count ( ) ;
2007-08-22 07:52:33 +00:00
}
/* ----- network ----- */
2011-03-28 18:11:28 +00:00
static void netaddr_to_sockaddr_in ( const NETADDR * src , struct sockaddr_in * dest )
2007-08-22 07:52:33 +00:00
{
2011-03-28 18:11:28 +00:00
mem_zero ( dest , sizeof ( struct sockaddr_in ) ) ;
2015-02-07 22:15:58 +00:00
if ( src - > type ! = NETTYPE_IPV4 & & src - > type ! = NETTYPE_WEBSOCKET_IPV4 )
2011-03-28 18:11:28 +00:00
{
dbg_msg ( " system " , " couldn't convert NETADDR of type %d to ipv4 " , src - > type ) ;
return ;
}
dest - > sin_family = AF_INET ;
dest - > sin_port = htons ( src - > port ) ;
mem_copy ( & dest - > sin_addr . s_addr , src - > ip , 4 ) ;
}
static void netaddr_to_sockaddr_in6 ( const NETADDR * src , struct sockaddr_in6 * dest )
{
mem_zero ( dest , sizeof ( struct sockaddr_in6 ) ) ;
if ( src - > type ! = NETTYPE_IPV6 )
{
dbg_msg ( " system " , " couldn't not convert NETADDR of type %d to ipv6 " , src - > type ) ;
return ;
}
dest - > sin6_family = AF_INET6 ;
dest - > sin6_port = htons ( src - > port ) ;
mem_copy ( & dest - > sin6_addr . s6_addr , src - > ip , 16 ) ;
2007-08-22 07:52:33 +00:00
}
2008-07-06 11:21:21 +00:00
static void sockaddr_to_netaddr ( const struct sockaddr * src , NETADDR * dst )
2007-08-22 07:52:33 +00:00
{
2020-10-12 16:59:58 +00:00
// Filled by accept, clang-analyzer probably can't tell because of the
// (struct sockaddr *) cast.
if ( src - > sa_family = = AF_INET ) // NOLINT(clang-analyzer-core.UndefinedBinaryOperatorResult)
2011-03-28 18:11:28 +00:00
{
mem_zero ( dst , sizeof ( NETADDR ) ) ;
dst - > type = NETTYPE_IPV4 ;
2020-09-26 19:41:58 +00:00
dst - > port = htons ( ( ( struct sockaddr_in * ) src ) - > sin_port ) ;
mem_copy ( dst - > ip , & ( ( struct sockaddr_in * ) src ) - > sin_addr . s_addr , 4 ) ;
2011-03-28 18:11:28 +00:00
}
2015-02-07 22:15:58 +00:00
else if ( src - > sa_family = = AF_WEBSOCKET_INET )
{
mem_zero ( dst , sizeof ( NETADDR ) ) ;
dst - > type = NETTYPE_WEBSOCKET_IPV4 ;
2020-09-26 19:41:58 +00:00
dst - > port = htons ( ( ( struct sockaddr_in * ) src ) - > sin_port ) ;
mem_copy ( dst - > ip , & ( ( struct sockaddr_in * ) src ) - > sin_addr . s_addr , 4 ) ;
2015-02-07 22:15:58 +00:00
}
2011-03-28 18:11:28 +00:00
else if ( src - > sa_family = = AF_INET6 )
{
mem_zero ( dst , sizeof ( NETADDR ) ) ;
dst - > type = NETTYPE_IPV6 ;
2020-09-26 19:41:58 +00:00
dst - > port = htons ( ( ( struct sockaddr_in6 * ) src ) - > sin6_port ) ;
mem_copy ( dst - > ip , & ( ( struct sockaddr_in6 * ) src ) - > sin6_addr . s6_addr , 16 ) ;
2011-03-28 18:11:28 +00:00
}
else
{
mem_zero ( dst , sizeof ( struct sockaddr ) ) ;
dbg_msg ( " system " , " couldn't convert sockaddr of family %d " , src - > sa_family ) ;
}
2007-08-22 07:52:33 +00:00
}
2008-07-06 11:21:21 +00:00
int net_addr_comp ( const NETADDR * a , const NETADDR * b )
2007-08-22 07:52:33 +00:00
{
2008-07-06 11:21:21 +00:00
return mem_comp ( a , b , sizeof ( NETADDR ) ) ;
2007-08-22 07:52:33 +00:00
}
2018-10-08 16:56:51 +00:00
int net_addr_comp_noport ( const NETADDR * a , const NETADDR * b )
2018-10-07 22:59:07 +00:00
{
2018-10-08 16:56:51 +00:00
NETADDR ta = * a , tb = * b ;
ta . port = tb . port = 0 ;
return net_addr_comp ( & ta , & tb ) ;
2018-10-07 22:59:07 +00:00
}
2021-05-05 16:22:52 +00:00
void net_addr_str_v6 ( const unsigned short ip [ 8 ] , int port , char * buffer , int buffer_size )
{
int longest_seq_len = 0 ;
int longest_seq_start = - 1 ;
int w = 0 ;
int i ;
{
int seq_len = 0 ;
int seq_start = - 1 ;
// Determine longest sequence of zeros.
for ( i = 0 ; i < 8 + 1 ; i + + )
{
if ( seq_start ! = - 1 )
{
if ( i = = 8 | | ip [ i ] ! = 0 )
{
if ( longest_seq_len < seq_len )
{
longest_seq_len = seq_len ;
longest_seq_start = seq_start ;
}
seq_len = 0 ;
seq_start = - 1 ;
}
else
{
seq_len + = 1 ;
}
}
else
{
if ( i ! = 8 & & ip [ i ] = = 0 )
{
seq_start = i ;
seq_len = 1 ;
}
}
}
}
if ( longest_seq_len < = 1 )
{
longest_seq_len = 0 ;
longest_seq_start = - 1 ;
}
w + = str_format ( buffer + w , buffer_size - w , " [ " ) ;
for ( i = 0 ; i < 8 ; i + + )
{
if ( longest_seq_start < = i & & i < longest_seq_start + longest_seq_len )
{
if ( i = = longest_seq_start )
{
w + = str_format ( buffer + w , buffer_size - w , " :: " ) ;
}
}
else
{
2021-06-15 01:24:23 +00:00
const char * colon = ( i = = 0 | | i = = longest_seq_start + longest_seq_len ) ? " " : " : " ;
2021-05-05 16:22:52 +00:00
w + = str_format ( buffer + w , buffer_size - w , " %s%x " , colon , ip [ i ] ) ;
}
}
w + = str_format ( buffer + w , buffer_size - w , " ] " ) ;
if ( port > = 0 )
{
str_format ( buffer + w , buffer_size - w , " :%d " , port ) ;
}
}
2011-12-29 22:36:53 +00:00
void net_addr_str ( const NETADDR * addr , char * string , int max_length , int add_port )
2008-08-17 07:05:16 +00:00
{
2015-02-07 22:15:58 +00:00
if ( addr - > type = = NETTYPE_IPV4 | | addr - > type = = NETTYPE_WEBSOCKET_IPV4 )
2011-04-22 17:52:27 +00:00
{
2011-12-29 22:36:53 +00:00
if ( add_port ! = 0 )
2011-04-22 17:52:27 +00:00
str_format ( string , max_length , " %d.%d.%d.%d:%d " , addr - > ip [ 0 ] , addr - > ip [ 1 ] , addr - > ip [ 2 ] , addr - > ip [ 3 ] , addr - > port ) ;
else
str_format ( string , max_length , " %d.%d.%d.%d " , addr - > ip [ 0 ] , addr - > ip [ 1 ] , addr - > ip [ 2 ] , addr - > ip [ 3 ] ) ;
}
2008-08-17 07:05:16 +00:00
else if ( addr - > type = = NETTYPE_IPV6 )
{
2021-05-05 16:22:52 +00:00
int port = - 1 ;
unsigned short ip [ 8 ] ;
int i ;
if ( add_port )
{
port = addr - > port ;
}
for ( i = 0 ; i < 8 ; i + + )
{
ip [ i ] = ( addr - > ip [ i * 2 ] < < 8 ) | ( addr - > ip [ i * 2 + 1 ] ) ;
}
net_addr_str_v6 ( ip , port , string , max_length ) ;
2008-08-17 07:05:16 +00:00
}
else
str_format ( string , max_length , " unknown type %d " , addr - > type ) ;
}
2011-03-28 18:11:28 +00:00
static int priv_net_extract ( const char * hostname , char * host , int max_host , int * port )
{
int i ;
* port = 0 ;
host [ 0 ] = 0 ;
if ( hostname [ 0 ] = = ' [ ' )
{
// ipv6 mode
2011-03-30 10:08:33 +00:00
for ( i = 1 ; i < max_host & & hostname [ i ] & & hostname [ i ] ! = ' ] ' ; i + + )
2020-09-26 19:41:58 +00:00
host [ i - 1 ] = hostname [ i ] ;
host [ i - 1 ] = 0 ;
2011-03-28 18:11:28 +00:00
if ( hostname [ i ] ! = ' ] ' ) // malformatted
return - 1 ;
i + + ;
if ( hostname [ i ] = = ' : ' )
2020-09-26 19:41:58 +00:00
* port = atol ( hostname + i + 1 ) ;
2011-03-28 18:11:28 +00:00
}
else
{
// generic mode (ipv4, hostname etc)
2020-09-26 19:41:58 +00:00
for ( i = 0 ; i < max_host - 1 & & hostname [ i ] & & hostname [ i ] ! = ' : ' ; i + + )
2011-03-28 18:11:28 +00:00
host [ i ] = hostname [ i ] ;
host [ i ] = 0 ;
if ( hostname [ i ] = = ' : ' )
2020-09-26 19:41:58 +00:00
* port = atol ( hostname + i + 1 ) ;
2011-03-28 18:11:28 +00:00
}
return 0 ;
}
2008-07-06 11:21:21 +00:00
int net_host_lookup ( const char * hostname , NETADDR * addr , int types )
2007-08-22 07:52:33 +00:00
{
2008-02-24 16:03:58 +00:00
struct addrinfo hints ;
2014-12-28 00:40:15 +00:00
struct addrinfo * result = NULL ;
2008-02-24 16:03:58 +00:00
int e ;
2011-03-28 18:11:28 +00:00
char host [ 256 ] ;
int port = 0 ;
if ( priv_net_extract ( hostname , host , sizeof ( host ) , & port ) )
return - 1 ;
2014-12-10 02:39:15 +00:00
2020-10-26 08:57:41 +00:00
dbg_msg ( " host_lookup " , " host='%s' port=%d %d " , host , port , types ) ;
2011-04-13 18:37:12 +00:00
2008-02-24 16:03:58 +00:00
mem_zero ( & hints , sizeof ( hints ) ) ;
2011-04-13 18:37:12 +00:00
2011-03-28 18:11:28 +00:00
hints . ai_family = AF_UNSPEC ;
if ( types = = NETTYPE_IPV4 )
hints . ai_family = AF_INET ;
else if ( types = = NETTYPE_IPV6 )
hints . ai_family = AF_INET6 ;
2020-09-18 14:25:00 +00:00
# if defined(CONF_WEBSOCKETS)
if ( types & NETTYPE_WEBSOCKET_IPV4 )
hints . ai_family = AF_INET ;
# endif
2007-08-22 07:52:33 +00:00
2011-03-28 18:11:28 +00:00
e = getaddrinfo ( host , NULL , & hints , & result ) ;
2013-08-07 23:47:49 +00:00
2014-12-28 00:40:15 +00:00
if ( ! result )
2008-02-24 16:03:58 +00:00
return - 1 ;
2007-08-22 07:52:33 +00:00
2014-12-28 00:40:15 +00:00
if ( e ! = 0 )
{
freeaddrinfo ( result ) ;
return - 1 ;
}
2008-07-06 11:21:21 +00:00
sockaddr_to_netaddr ( result - > ai_addr , addr ) ;
2011-03-28 18:11:28 +00:00
addr - > port = port ;
2013-08-07 23:47:49 +00:00
freeaddrinfo ( result ) ;
2008-02-24 16:03:58 +00:00
return 0 ;
2007-08-22 07:52:33 +00:00
}
2008-09-03 21:02:30 +00:00
static int parse_int ( int * out , const char * * str )
{
int i = 0 ;
* out = 0 ;
if ( * * str < ' 0 ' | | * * str > ' 9 ' )
2011-04-13 18:37:12 +00:00
return - 1 ;
2008-09-03 21:02:30 +00:00
i = * * str - ' 0 ' ;
( * str ) + + ;
2022-02-14 23:12:52 +00:00
while ( true )
2008-09-03 21:02:30 +00:00
{
if ( * * str < ' 0 ' | | * * str > ' 9 ' )
{
* out = i ;
2011-04-13 18:37:12 +00:00
return 0 ;
2008-09-03 21:02:30 +00:00
}
2011-04-13 18:37:12 +00:00
2020-09-26 19:41:58 +00:00
i = ( i * 10 ) + ( * * str - ' 0 ' ) ;
2008-09-03 21:02:30 +00:00
( * str ) + + ;
}
return 0 ;
}
static int parse_char ( char c , const char * * str )
{
2020-09-26 19:41:58 +00:00
if ( * * str ! = c )
return - 1 ;
2008-09-03 21:02:30 +00:00
( * str ) + + ;
return 0 ;
}
static int parse_uint8 ( unsigned char * out , const char * * str )
{
int i ;
2020-09-26 19:41:58 +00:00
if ( parse_int ( & i , str ) ! = 0 )
return - 1 ;
if ( i < 0 | | i > 0xff )
return - 1 ;
2008-09-03 21:02:30 +00:00
* out = i ;
return 0 ;
}
static int parse_uint16 ( unsigned short * out , const char * * str )
{
int i ;
2020-09-26 19:41:58 +00:00
if ( parse_int ( & i , str ) ! = 0 )
return - 1 ;
if ( i < 0 | | i > 0xffff )
return - 1 ;
2008-09-03 21:02:30 +00:00
* out = i ;
return 0 ;
}
int net_addr_from_str ( NETADDR * addr , const char * string )
{
const char * str = string ;
mem_zero ( addr , sizeof ( NETADDR ) ) ;
2011-04-13 18:37:12 +00:00
2008-09-03 21:02:30 +00:00
if ( str [ 0 ] = = ' [ ' )
{
2011-03-28 18:11:28 +00:00
/* ipv6 */
struct sockaddr_in6 sa6 ;
char buf [ 128 ] ;
2011-03-28 20:08:52 +00:00
int i ;
2011-03-30 10:08:33 +00:00
str + + ;
2011-03-28 18:11:28 +00:00
for ( i = 0 ; i < 127 & & str [ i ] & & str [ i ] ! = ' ] ' ; i + + )
buf [ i ] = str [ i ] ;
buf [ i ] = 0 ;
str + = i ;
# if defined(CONF_FAMILY_WINDOWS)
2011-03-28 20:08:52 +00:00
{
int size ;
sa6 . sin6_family = AF_INET6 ;
size = ( int ) sizeof ( sa6 ) ;
2021-11-20 11:39:52 +00:00
if ( WSAStringToAddressA ( buf , AF_INET6 , NULL , ( struct sockaddr * ) & sa6 , & size ) ! = 0 )
2011-03-28 20:08:52 +00:00
return - 1 ;
}
2011-03-28 18:11:28 +00:00
# else
2015-07-12 01:08:58 +00:00
sa6 . sin6_family = AF_INET6 ;
if ( inet_pton ( AF_INET6 , buf , & sa6 . sin6_addr ) ! = 1 )
2011-03-28 18:11:28 +00:00
return - 1 ;
# endif
sockaddr_to_netaddr ( ( struct sockaddr * ) & sa6 , addr ) ;
if ( * str = = ' ] ' )
{
str + + ;
if ( * str = = ' : ' )
{
str + + ;
if ( parse_uint16 ( & addr - > port , & str ) )
return - 1 ;
}
2021-04-17 14:03:12 +00:00
else
{
addr - > port = 0 ;
}
2011-03-28 18:11:28 +00:00
}
else
return - 1 ;
return 0 ;
2008-09-03 21:02:30 +00:00
}
else
{
/* ipv4 */
2020-09-26 19:41:58 +00:00
if ( parse_uint8 ( & addr - > ip [ 0 ] , & str ) )
return - 1 ;
if ( parse_char ( ' . ' , & str ) )
return - 1 ;
if ( parse_uint8 ( & addr - > ip [ 1 ] , & str ) )
return - 1 ;
if ( parse_char ( ' . ' , & str ) )
return - 1 ;
if ( parse_uint8 ( & addr - > ip [ 2 ] , & str ) )
return - 1 ;
if ( parse_char ( ' . ' , & str ) )
return - 1 ;
if ( parse_uint8 ( & addr - > ip [ 3 ] , & str ) )
return - 1 ;
2008-09-03 21:02:30 +00:00
if ( * str = = ' : ' )
{
str + + ;
2020-09-26 19:41:58 +00:00
if ( parse_uint16 ( & addr - > port , & str ) )
return - 1 ;
2008-09-03 21:02:30 +00:00
}
2021-07-25 22:30:01 +00:00
if ( * str ! = ' \0 ' )
2021-07-25 22:13:05 +00:00
return - 1 ;
2011-04-13 18:37:12 +00:00
2008-09-03 21:02:30 +00:00
addr - > type = NETTYPE_IPV4 ;
}
2011-04-13 18:37:12 +00:00
2008-09-03 21:02:30 +00:00
return 0 ;
}
2011-03-28 18:11:28 +00:00
static void priv_net_close_socket ( int sock )
{
# if defined(CONF_FAMILY_WINDOWS)
closesocket ( sock ) ;
# else
2019-03-19 10:44:16 +00:00
if ( close ( sock ) ! = 0 )
dbg_msg ( " socket " , " close failed: %d " , errno ) ;
2011-03-28 18:11:28 +00:00
# endif
}
2008-09-03 21:02:30 +00:00
2011-03-28 18:11:28 +00:00
static int priv_net_close_all_sockets ( NETSOCKET sock )
2007-08-22 07:52:33 +00:00
{
2011-03-28 18:11:28 +00:00
/* close down ipv4 */
2022-03-01 16:34:42 +00:00
if ( sock - > ipv4sock > = 0 )
2011-03-28 18:11:28 +00:00
{
2022-03-01 16:34:42 +00:00
priv_net_close_socket ( sock - > ipv4sock ) ;
sock - > ipv4sock = - 1 ;
sock - > type & = ~ NETTYPE_IPV4 ;
2011-03-28 18:11:28 +00:00
}
2017-03-07 12:03:37 +00:00
# if defined(CONF_WEBSOCKETS)
2015-02-07 22:15:58 +00:00
/* close down websocket_ipv4 */
2022-03-01 16:34:42 +00:00
if ( sock - > web_ipv4sock > = 0 )
2015-02-07 22:15:58 +00:00
{
2022-03-01 18:27:48 +00:00
websocket_destroy ( sock - > web_ipv4sock ) ;
2022-03-01 16:34:42 +00:00
sock - > web_ipv4sock = - 1 ;
sock - > type & = ~ NETTYPE_WEBSOCKET_IPV4 ;
2015-02-07 22:15:58 +00:00
}
# endif
2011-03-28 18:11:28 +00:00
/* close down ipv6 */
2022-03-01 16:34:42 +00:00
if ( sock - > ipv6sock > = 0 )
2011-03-28 18:11:28 +00:00
{
2022-03-01 16:34:42 +00:00
priv_net_close_socket ( sock - > ipv6sock ) ;
sock - > ipv6sock = - 1 ;
sock - > type & = ~ NETTYPE_IPV6 ;
2011-03-28 18:11:28 +00:00
}
2022-03-01 16:34:42 +00:00
free ( sock ) ;
2011-03-28 18:11:28 +00:00
return 0 ;
}
static int priv_net_create_socket ( int domain , int type , struct sockaddr * addr , int sockaddrlen )
{
int sock , e ;
2007-08-22 07:52:33 +00:00
/* create socket */
2011-03-28 18:11:28 +00:00
sock = socket ( domain , type , 0 ) ;
2007-08-22 07:52:33 +00:00
if ( sock < 0 )
{
2011-12-04 16:09:30 +00:00
# if defined(CONF_FAMILY_WINDOWS)
char buf [ 128 ] ;
2021-11-20 15:37:03 +00:00
WCHAR wBuffer [ 128 ] ;
2011-12-04 16:09:30 +00:00
int error = WSAGetLastError ( ) ;
2022-03-30 13:16:19 +00:00
if ( FormatMessageW ( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS , 0 , error , 0 , wBuffer , std : : size ( wBuffer ) , 0 ) = = 0 )
2021-11-20 15:37:03 +00:00
wBuffer [ 0 ] = 0 ;
2021-11-21 09:34:11 +00:00
WideCharToMultiByte ( CP_UTF8 , 0 , wBuffer , - 1 , buf , sizeof ( buf ) , NULL , NULL ) ;
2011-12-04 16:09:30 +00:00
dbg_msg ( " net " , " failed to create socket with domain %d and type %d (%d '%s') " , domain , type , error , buf ) ;
# else
2011-03-28 18:11:28 +00:00
dbg_msg ( " net " , " failed to create socket with domain %d and type %d (%d '%s') " , domain , type , errno , strerror ( errno ) ) ;
2011-12-04 16:09:30 +00:00
# endif
2011-03-28 18:11:28 +00:00
return - 1 ;
}
2015-06-13 09:49:35 +00:00
# if defined(CONF_FAMILY_UNIX)
/* on tcp sockets set SO_REUSEADDR
to fix port rebind on restart */
2020-09-26 19:41:58 +00:00
if ( domain = = AF_INET & & type = = SOCK_STREAM )
2015-06-13 09:49:35 +00:00
{
int option = 1 ;
2019-03-19 10:44:16 +00:00
if ( setsockopt ( sock , SOL_SOCKET , SO_REUSEADDR , & option , sizeof ( option ) ) ! = 0 )
dbg_msg ( " socket " , " Setting SO_REUSEADDR failed: %d " , errno ) ;
2015-06-13 09:49:35 +00:00
}
# endif
2018-07-10 09:29:02 +00:00
/* set to IPv6 only if that's what we are creating */
2020-09-26 19:41:58 +00:00
# if defined(IPV6_V6ONLY) /* windows sdk 6.1 and higher */
2011-03-28 18:11:28 +00:00
if ( domain = = AF_INET6 )
{
int ipv6only = 1 ;
2020-09-26 19:41:58 +00:00
if ( setsockopt ( sock , IPPROTO_IPV6 , IPV6_V6ONLY , ( const char * ) & ipv6only , sizeof ( ipv6only ) ) ! = 0 )
2019-03-19 10:44:16 +00:00
dbg_msg ( " socket " , " Setting V6ONLY failed: %d " , errno ) ;
2011-03-28 18:11:28 +00:00
}
2011-06-18 15:27:14 +00:00
# endif
2011-03-28 18:11:28 +00:00
/* bind the socket */
e = bind ( sock , addr , sockaddrlen ) ;
if ( e ! = 0 )
{
2011-12-04 16:09:30 +00:00
# if defined(CONF_FAMILY_WINDOWS)
char buf [ 128 ] ;
2021-11-20 15:37:03 +00:00
WCHAR wBuffer [ 128 ] ;
2011-12-04 16:09:30 +00:00
int error = WSAGetLastError ( ) ;
2022-03-30 13:16:19 +00:00
if ( FormatMessageW ( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS , 0 , error , 0 , wBuffer , std : : size ( wBuffer ) , 0 ) = = 0 )
2021-11-20 15:37:03 +00:00
wBuffer [ 0 ] = 0 ;
2021-11-21 09:34:11 +00:00
WideCharToMultiByte ( CP_UTF8 , 0 , wBuffer , - 1 , buf , sizeof ( buf ) , NULL , NULL ) ;
2011-12-04 16:12:44 +00:00
dbg_msg ( " net " , " failed to bind socket with domain %d and type %d (%d '%s') " , domain , type , error , buf ) ;
2011-12-04 16:09:30 +00:00
# else
2011-03-28 18:11:28 +00:00
dbg_msg ( " net " , " failed to bind socket with domain %d and type %d (%d '%s') " , domain , type , errno , strerror ( errno ) ) ;
2011-12-04 16:09:30 +00:00
# endif
2011-03-28 18:11:28 +00:00
priv_net_close_socket ( sock ) ;
return - 1 ;
2007-08-22 07:52:33 +00:00
}
2011-04-13 18:37:12 +00:00
2011-03-28 18:11:28 +00:00
/* return the newly created socket */
return sock ;
}
2022-03-01 16:34:42 +00:00
int net_socket_type ( NETSOCKET sock )
{
return sock - > type ;
}
2011-03-28 18:11:28 +00:00
NETSOCKET net_udp_create ( NETADDR bindaddr )
{
2022-03-01 16:34:42 +00:00
NETSOCKET sock = ( NETSOCKET_INTERNAL * ) malloc ( sizeof ( * sock ) ) ;
* sock = invalid_socket ;
2011-03-28 18:11:28 +00:00
NETADDR tmpbindaddr = bindaddr ;
2011-07-06 16:20:46 +00:00
int broadcast = 1 ;
2022-05-28 22:41:20 +00:00
int socket = - 1 ;
2011-03-28 18:11:28 +00:00
2020-09-26 19:41:58 +00:00
if ( bindaddr . type & NETTYPE_IPV4 )
2011-03-28 18:11:28 +00:00
{
struct sockaddr_in addr ;
/* bind, we should check for error */
tmpbindaddr . type = NETTYPE_IPV4 ;
netaddr_to_sockaddr_in ( & tmpbindaddr , & addr ) ;
socket = priv_net_create_socket ( AF_INET , SOCK_DGRAM , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
if ( socket > = 0 )
{
2022-03-01 16:34:42 +00:00
sock - > type | = NETTYPE_IPV4 ;
sock - > ipv4sock = socket ;
2011-07-06 16:20:46 +00:00
2017-10-24 11:40:35 +00:00
/* set broadcast */
2020-09-26 19:41:58 +00:00
if ( setsockopt ( socket , SOL_SOCKET , SO_BROADCAST , ( const char * ) & broadcast , sizeof ( broadcast ) ) ! = 0 )
2019-03-19 10:44:16 +00:00
dbg_msg ( " socket " , " Setting BROADCAST on ipv4 failed: %d " , errno ) ;
2011-07-06 16:20:46 +00:00
2014-12-08 17:44:01 +00:00
{
/* set DSCP/TOS */
int iptos = 0x10 /* IPTOS_LOWDELAY */ ;
//int iptos = 46; /* High Priority */
2020-09-26 19:41:58 +00:00
if ( setsockopt ( socket , IPPROTO_IP , IP_TOS , ( char * ) & iptos , sizeof ( iptos ) ) ! = 0 )
2019-03-19 10:44:16 +00:00
dbg_msg ( " socket " , " Setting TOS on ipv4 failed: %d " , errno ) ;
2014-12-08 17:44:01 +00:00
}
2013-02-24 16:14:55 +00:00
}
2011-03-28 18:11:28 +00:00
}
2017-03-07 12:03:37 +00:00
# if defined(CONF_WEBSOCKETS)
2020-09-26 19:41:58 +00:00
if ( bindaddr . type & NETTYPE_WEBSOCKET_IPV4 )
2015-02-07 22:15:58 +00:00
{
2017-07-22 19:20:15 +00:00
char addr_str [ NETADDR_MAXSTRSIZE ] ;
2015-02-07 22:15:58 +00:00
/* bind, we should check for error */
tmpbindaddr . type = NETTYPE_WEBSOCKET_IPV4 ;
net_addr_str ( & tmpbindaddr , addr_str , sizeof ( addr_str ) , 0 ) ;
socket = websocket_create ( addr_str , tmpbindaddr . port ) ;
2020-09-26 19:41:58 +00:00
if ( socket > = 0 )
{
2022-03-01 16:34:42 +00:00
sock - > type | = NETTYPE_WEBSOCKET_IPV4 ;
sock - > web_ipv4sock = socket ;
2015-02-07 22:15:58 +00:00
}
}
# endif
2020-09-26 19:41:58 +00:00
if ( bindaddr . type & NETTYPE_IPV6 )
2011-03-28 18:11:28 +00:00
{
struct sockaddr_in6 addr ;
/* bind, we should check for error */
tmpbindaddr . type = NETTYPE_IPV6 ;
netaddr_to_sockaddr_in6 ( & tmpbindaddr , & addr ) ;
socket = priv_net_create_socket ( AF_INET6 , SOCK_DGRAM , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
if ( socket > = 0 )
{
2022-03-01 16:34:42 +00:00
sock - > type | = NETTYPE_IPV6 ;
sock - > ipv6sock = socket ;
2011-07-06 16:20:46 +00:00
2017-10-24 11:40:35 +00:00
/* set broadcast */
2020-09-26 19:41:58 +00:00
if ( setsockopt ( socket , SOL_SOCKET , SO_BROADCAST , ( const char * ) & broadcast , sizeof ( broadcast ) ) ! = 0 )
dbg_msg ( " socket " , " Setting BROADCAST on ipv6 failed: %d " , errno ) ;
2011-07-06 16:20:46 +00:00
2014-12-08 17:44:01 +00:00
{
/* set DSCP/TOS */
int iptos = 0x10 /* IPTOS_LOWDELAY */ ;
//int iptos = 46; /* High Priority */
2020-09-26 19:41:58 +00:00
if ( setsockopt ( socket , IPPROTO_IP , IP_TOS , ( char * ) & iptos , sizeof ( iptos ) ) ! = 0 )
2019-03-19 10:44:16 +00:00
dbg_msg ( " socket " , " Setting TOS on ipv6 failed: %d " , errno ) ;
2014-12-08 17:44:01 +00:00
}
2013-02-24 16:14:55 +00:00
}
2011-03-28 18:11:28 +00:00
}
2022-05-28 22:41:20 +00:00
if ( socket < 0 )
{
free ( sock ) ;
sock = nullptr ;
}
else
{
/* set non-blocking */
net_set_non_blocking ( sock ) ;
2013-02-24 16:14:55 +00:00
2022-05-28 22:41:20 +00:00
net_buffer_init ( & sock - > buffer ) ;
}
2022-03-01 18:13:35 +00:00
2007-08-22 07:52:33 +00:00
/* return */
return sock ;
}
2008-07-06 11:21:21 +00:00
int net_udp_send ( NETSOCKET sock , const NETADDR * addr , const void * data , int size )
2007-08-22 07:52:33 +00:00
{
2011-03-28 18:11:28 +00:00
int d = - 1 ;
2020-09-26 19:41:58 +00:00
if ( addr - > type & NETTYPE_IPV4 )
2011-03-28 18:11:28 +00:00
{
2022-03-01 16:34:42 +00:00
if ( sock - > ipv4sock > = 0 )
2011-03-28 18:11:28 +00:00
{
struct sockaddr_in sa ;
2020-09-26 19:41:58 +00:00
if ( addr - > type & NETTYPE_LINK_BROADCAST )
2011-03-28 18:11:28 +00:00
{
mem_zero ( & sa , sizeof ( sa ) ) ;
sa . sin_port = htons ( addr - > port ) ;
sa . sin_family = AF_INET ;
sa . sin_addr . s_addr = INADDR_BROADCAST ;
}
else
netaddr_to_sockaddr_in ( addr , & sa ) ;
2022-03-01 16:34:42 +00:00
d = sendto ( ( int ) sock - > ipv4sock , ( const char * ) data , size , 0 , ( struct sockaddr * ) & sa , sizeof ( sa ) ) ;
2011-03-28 18:11:28 +00:00
}
else
2015-06-16 19:39:22 +00:00
dbg_msg ( " net " , " can't send ipv4 traffic to this socket " ) ;
2011-03-28 18:11:28 +00:00
}
2017-03-07 12:03:37 +00:00
# if defined(CONF_WEBSOCKETS)
2020-09-12 15:12:00 +00:00
if ( addr - > type & NETTYPE_WEBSOCKET_IPV4 )
2015-02-07 22:15:58 +00:00
{
2022-03-01 16:34:42 +00:00
if ( sock - > web_ipv4sock > = 0 )
2020-09-12 15:12:00 +00:00
{
char addr_str [ NETADDR_MAXSTRSIZE ] ;
str_format ( addr_str , sizeof ( addr_str ) , " %d.%d.%d.%d " , addr - > ip [ 0 ] , addr - > ip [ 1 ] , addr - > ip [ 2 ] , addr - > ip [ 3 ] ) ;
2022-03-01 16:34:42 +00:00
d = websocket_send ( sock - > web_ipv4sock , ( const unsigned char * ) data , size , addr_str , addr - > port ) ;
2020-09-12 15:12:00 +00:00
}
2015-02-07 22:15:58 +00:00
else
2015-06-16 19:39:22 +00:00
dbg_msg ( " net " , " can't send websocket_ipv4 traffic to this socket " ) ;
2015-02-07 22:15:58 +00:00
}
# endif
2020-09-26 19:41:58 +00:00
if ( addr - > type & NETTYPE_IPV6 )
2011-03-28 18:11:28 +00:00
{
2022-03-01 16:34:42 +00:00
if ( sock - > ipv6sock > = 0 )
2011-03-28 18:11:28 +00:00
{
struct sockaddr_in6 sa ;
2020-09-26 19:41:58 +00:00
if ( addr - > type & NETTYPE_LINK_BROADCAST )
2011-03-28 18:11:28 +00:00
{
mem_zero ( & sa , sizeof ( sa ) ) ;
sa . sin6_port = htons ( addr - > port ) ;
sa . sin6_family = AF_INET6 ;
sa . sin6_addr . s6_addr [ 0 ] = 0xff ; /* multicast */
sa . sin6_addr . s6_addr [ 1 ] = 0x02 ; /* link local scope */
sa . sin6_addr . s6_addr [ 15 ] = 1 ; /* all nodes */
}
else
netaddr_to_sockaddr_in6 ( addr , & sa ) ;
2022-03-01 16:34:42 +00:00
d = sendto ( ( int ) sock - > ipv6sock , ( const char * ) data , size , 0 , ( struct sockaddr * ) & sa , sizeof ( sa ) ) ;
2011-03-28 18:11:28 +00:00
}
else
2015-06-16 19:39:22 +00:00
dbg_msg ( " net " , " can't send ipv6 traffic to this socket " ) ;
2011-03-28 18:11:28 +00:00
}
/*
else
2015-06-16 19:39:22 +00:00
dbg_msg ( " net " , " can't send to network of type %d " , addr - > type ) ;
2011-03-28 18:11:28 +00:00
*/
2010-05-29 07:25:38 +00:00
/*if(d < 0)
2008-08-17 07:05:16 +00:00
{
char addrstr [ 256 ] ;
net_addr_str ( addr , addrstr , sizeof ( addrstr ) ) ;
2011-04-13 18:37:12 +00:00
2011-03-28 18:11:28 +00:00
dbg_msg ( " net " , " sendto error (%d '%s') " , errno , strerror ( errno ) ) ;
2008-08-17 07:05:16 +00:00
dbg_msg ( " net " , " \t sock = %d %x " , sock , sock ) ;
dbg_msg ( " net " , " \t size = %d %x " , size , size ) ;
dbg_msg ( " net " , " \t addr = %s " , addrstr ) ;
2010-05-29 07:25:38 +00:00
} */
2008-04-05 14:50:43 +00:00
network_stats . sent_bytes + = size ;
network_stats . sent_packets + + ;
2007-08-22 07:52:33 +00:00
return d ;
}
2022-03-01 18:27:48 +00:00
void net_buffer_init ( NETSOCKET_BUFFER * buffer )
2018-07-25 14:06:00 +00:00
{
# if defined(CONF_PLATFORM_LINUX)
2018-12-17 13:44:19 +00:00
int i ;
2022-03-01 18:27:48 +00:00
buffer - > pos = 0 ;
buffer - > size = 0 ;
mem_zero ( buffer - > msgs , sizeof ( buffer - > msgs ) ) ;
mem_zero ( buffer - > iovecs , sizeof ( buffer - > iovecs ) ) ;
mem_zero ( buffer - > sockaddrs , sizeof ( buffer - > sockaddrs ) ) ;
2018-12-17 13:44:19 +00:00
for ( i = 0 ; i < VLEN ; + + i )
2018-07-25 14:06:00 +00:00
{
2022-03-01 18:27:48 +00:00
buffer - > iovecs [ i ] . iov_base = buffer - > bufs [ i ] ;
buffer - > iovecs [ i ] . iov_len = PACKETSIZE ;
buffer - > msgs [ i ] . msg_hdr . msg_iov = & ( buffer - > iovecs [ i ] ) ;
buffer - > msgs [ i ] . msg_hdr . msg_iovlen = 1 ;
buffer - > msgs [ i ] . msg_hdr . msg_name = & ( buffer - > sockaddrs [ i ] ) ;
buffer - > msgs [ i ] . msg_hdr . msg_namelen = sizeof ( buffer - > sockaddrs [ i ] ) ;
2018-07-25 14:06:00 +00:00
}
# endif
}
2022-03-01 18:27:48 +00:00
void net_buffer_simple ( NETSOCKET_BUFFER * buffer , char * * buf , int * size )
{
# if defined(CONF_PLATFORM_LINUX)
* buf = buffer - > bufs [ 0 ] ;
* size = sizeof ( buffer - > bufs [ 0 ] ) ;
# else
* buf = buffer - > buf ;
* size = sizeof ( buffer - > buf ) ;
# endif
}
int net_udp_recv ( NETSOCKET sock , NETADDR * addr , unsigned char * * data )
2007-08-22 07:52:33 +00:00
{
2011-03-28 18:11:28 +00:00
char sockaddrbuf [ 128 ] ;
int bytes = 0 ;
2018-07-25 14:06:00 +00:00
# if defined(CONF_PLATFORM_LINUX)
2022-03-01 16:34:42 +00:00
if ( sock - > ipv4sock > = 0 )
2018-07-25 14:06:00 +00:00
{
2022-03-01 18:27:48 +00:00
if ( sock - > buffer . pos > = sock - > buffer . size )
2018-07-25 14:06:00 +00:00
{
2022-03-01 18:27:48 +00:00
sock - > buffer . size = recvmmsg ( sock - > ipv4sock , sock - > buffer . msgs , VLEN , 0 , NULL ) ;
sock - > buffer . pos = 0 ;
2018-07-25 14:06:00 +00:00
}
}
2022-03-01 16:34:42 +00:00
if ( sock - > ipv6sock > = 0 )
2018-07-25 14:06:00 +00:00
{
2022-03-01 18:27:48 +00:00
if ( sock - > buffer . pos > = sock - > buffer . size )
2018-07-25 14:06:00 +00:00
{
2022-03-01 18:27:48 +00:00
sock - > buffer . size = recvmmsg ( sock - > ipv6sock , sock - > buffer . msgs , VLEN , 0 , NULL ) ;
sock - > buffer . pos = 0 ;
2018-07-25 14:06:00 +00:00
}
}
2022-03-01 18:27:48 +00:00
if ( sock - > buffer . pos < sock - > buffer . size )
2018-07-25 14:06:00 +00:00
{
2022-03-01 18:27:48 +00:00
sockaddr_to_netaddr ( ( struct sockaddr * ) & ( sock - > buffer . sockaddrs [ sock - > buffer . pos ] ) , addr ) ;
bytes = sock - > buffer . msgs [ sock - > buffer . pos ] . msg_len ;
* data = ( unsigned char * ) sock - > buffer . bufs [ sock - > buffer . pos ] ;
sock - > buffer . pos + + ;
2021-01-09 10:48:05 +00:00
network_stats . recv_bytes + = bytes ;
network_stats . recv_packets + + ;
2018-07-25 14:06:00 +00:00
return bytes ;
}
# else
2022-03-01 16:34:42 +00:00
if ( bytes = = 0 & & sock - > ipv4sock > = 0 )
2011-03-28 18:11:28 +00:00
{
2018-12-17 16:27:36 +00:00
socklen_t fromlen = sizeof ( struct sockaddr_in ) ;
2022-03-01 18:27:48 +00:00
bytes = recvfrom ( sock - > ipv4sock , sock - > buffer . buf , sizeof ( sock - > buffer . buf ) , 0 , ( struct sockaddr * ) & sockaddrbuf , & fromlen ) ;
* data = ( unsigned char * ) sock - > buffer . buf ;
2011-03-28 18:11:28 +00:00
}
2022-03-01 16:34:42 +00:00
if ( bytes < = 0 & & sock - > ipv6sock > = 0 )
2011-03-28 18:11:28 +00:00
{
2018-12-17 16:27:36 +00:00
socklen_t fromlen = sizeof ( struct sockaddr_in6 ) ;
2022-03-01 18:27:48 +00:00
bytes = recvfrom ( sock - > ipv6sock , sock - > buffer . buf , sizeof ( sock - > buffer . buf ) , 0 , ( struct sockaddr * ) & sockaddrbuf , & fromlen ) ;
* data = ( unsigned char * ) sock - > buffer . buf ;
2011-03-28 18:11:28 +00:00
}
2018-07-25 14:06:00 +00:00
# endif
2011-03-28 18:11:28 +00:00
2017-03-07 12:03:37 +00:00
# if defined(CONF_WEBSOCKETS)
2022-03-01 16:34:42 +00:00
if ( bytes < = 0 & & sock - > web_ipv4sock > = 0 )
2015-02-07 22:15:58 +00:00
{
2022-03-01 18:27:48 +00:00
char * buf ;
int size ;
net_buffer_simple ( & sock - > buffer , & buf , & size ) ;
2018-12-17 16:27:36 +00:00
socklen_t fromlen = sizeof ( struct sockaddr ) ;
2019-12-30 09:12:16 +00:00
struct sockaddr_in * sockaddrbuf_in = ( struct sockaddr_in * ) & sockaddrbuf ;
2022-03-01 18:27:48 +00:00
bytes = websocket_recv ( sock - > web_ipv4sock , ( unsigned char * ) buf , size , sockaddrbuf_in , fromlen ) ;
* data = ( unsigned char * ) buf ;
2019-12-30 09:12:16 +00:00
sockaddrbuf_in - > sin_family = AF_WEBSOCKET_INET ;
2015-02-07 22:15:58 +00:00
}
# endif
2007-08-22 07:52:33 +00:00
if ( bytes > 0 )
{
2011-03-28 18:11:28 +00:00
sockaddr_to_netaddr ( ( struct sockaddr * ) & sockaddrbuf , addr ) ;
2008-04-05 14:50:43 +00:00
network_stats . recv_bytes + = bytes ;
network_stats . recv_packets + + ;
2007-08-22 07:52:33 +00:00
return bytes ;
}
else if ( bytes = = 0 )
return 0 ;
return - 1 ; /* error */
}
2008-07-06 11:21:21 +00:00
int net_udp_close ( NETSOCKET sock )
2007-08-22 07:52:33 +00:00
{
2011-03-28 18:11:28 +00:00
return priv_net_close_all_sockets ( sock ) ;
2007-08-22 07:52:33 +00:00
}
2011-07-06 16:20:46 +00:00
NETSOCKET net_tcp_create ( NETADDR bindaddr )
2007-08-22 07:52:33 +00:00
{
2022-03-01 16:34:42 +00:00
NETSOCKET sock = ( NETSOCKET_INTERNAL * ) malloc ( sizeof ( * sock ) ) ;
* sock = invalid_socket ;
2011-07-06 16:20:46 +00:00
NETADDR tmpbindaddr = bindaddr ;
2022-05-28 22:41:20 +00:00
int socket = - 1 ;
2007-08-22 07:52:33 +00:00
2020-09-26 19:41:58 +00:00
if ( bindaddr . type & NETTYPE_IPV4 )
2011-03-28 18:11:28 +00:00
{
struct sockaddr_in addr ;
2007-08-22 07:52:33 +00:00
2011-07-06 16:20:46 +00:00
/* bind, we should check for error */
tmpbindaddr . type = NETTYPE_IPV4 ;
netaddr_to_sockaddr_in ( & tmpbindaddr , & addr ) ;
socket = priv_net_create_socket ( AF_INET , SOCK_STREAM , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
if ( socket > = 0 )
{
2022-03-01 16:34:42 +00:00
sock - > type | = NETTYPE_IPV4 ;
sock - > ipv4sock = socket ;
2011-07-06 16:20:46 +00:00
}
}
2020-09-26 19:41:58 +00:00
if ( bindaddr . type & NETTYPE_IPV6 )
2011-07-06 16:20:46 +00:00
{
struct sockaddr_in6 addr ;
2007-08-22 07:52:33 +00:00
2011-03-28 18:11:28 +00:00
/* bind, we should check for error */
2011-07-06 16:20:46 +00:00
tmpbindaddr . type = NETTYPE_IPV6 ;
netaddr_to_sockaddr_in6 ( & tmpbindaddr , & addr ) ;
socket = priv_net_create_socket ( AF_INET6 , SOCK_STREAM , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
if ( socket > = 0 )
{
2022-03-01 16:34:42 +00:00
sock - > type | = NETTYPE_IPV6 ;
sock - > ipv6sock = socket ;
2011-07-06 16:20:46 +00:00
}
2011-03-28 18:11:28 +00:00
}
2007-08-22 07:52:33 +00:00
2022-05-28 22:41:20 +00:00
if ( socket < 0 )
{
free ( sock ) ;
sock = nullptr ;
}
2011-04-13 18:37:12 +00:00
/* return */
return sock ;
2007-08-22 07:52:33 +00:00
}
2011-07-06 16:20:46 +00:00
int net_set_non_blocking ( NETSOCKET sock )
2007-08-22 07:52:33 +00:00
{
2010-08-16 00:21:18 +00:00
unsigned long mode = 1 ;
2022-03-01 16:34:42 +00:00
if ( sock - > ipv4sock > = 0 )
2011-03-28 18:11:28 +00:00
{
# if defined(CONF_FAMILY_WINDOWS)
2022-03-01 16:34:42 +00:00
ioctlsocket ( sock - > ipv4sock , FIONBIO , ( unsigned long * ) & mode ) ;
2011-03-28 18:11:28 +00:00
# else
2022-03-01 16:34:42 +00:00
if ( ioctl ( sock - > ipv4sock , FIONBIO , ( unsigned long * ) & mode ) = = - 1 )
2019-03-19 10:44:16 +00:00
dbg_msg ( " socket " , " setting ipv4 non-blocking failed: %d " , errno ) ;
2011-03-28 18:11:28 +00:00
# endif
}
2022-03-01 16:34:42 +00:00
if ( sock - > ipv6sock > = 0 )
2011-03-28 18:11:28 +00:00
{
2007-08-22 07:52:33 +00:00
# if defined(CONF_FAMILY_WINDOWS)
2022-03-01 16:34:42 +00:00
ioctlsocket ( sock - > ipv6sock , FIONBIO , ( unsigned long * ) & mode ) ;
2007-08-22 07:52:33 +00:00
# else
2022-03-01 16:34:42 +00:00
if ( ioctl ( sock - > ipv6sock , FIONBIO , ( unsigned long * ) & mode ) = = - 1 )
2019-03-19 10:44:16 +00:00
dbg_msg ( " socket " , " setting ipv6 non-blocking failed: %d " , errno ) ;
2007-08-22 07:52:33 +00:00
# endif
2011-03-28 18:11:28 +00:00
}
return 0 ;
2007-08-22 07:52:33 +00:00
}
2011-07-06 16:20:46 +00:00
int net_set_blocking ( NETSOCKET sock )
2007-08-22 07:52:33 +00:00
{
2010-08-16 00:21:18 +00:00
unsigned long mode = 0 ;
2022-03-01 16:34:42 +00:00
if ( sock - > ipv4sock > = 0 )
2011-03-28 18:11:28 +00:00
{
2007-08-22 07:52:33 +00:00
# if defined(CONF_FAMILY_WINDOWS)
2022-03-01 16:34:42 +00:00
ioctlsocket ( sock - > ipv4sock , FIONBIO , ( unsigned long * ) & mode ) ;
2007-08-22 07:52:33 +00:00
# else
2022-03-01 16:34:42 +00:00
if ( ioctl ( sock - > ipv4sock , FIONBIO , ( unsigned long * ) & mode ) = = - 1 )
2019-03-19 10:44:16 +00:00
dbg_msg ( " socket " , " setting ipv4 blocking failed: %d " , errno ) ;
2007-08-22 07:52:33 +00:00
# endif
2011-03-28 18:11:28 +00:00
}
2022-03-01 16:34:42 +00:00
if ( sock - > ipv6sock > = 0 )
2011-03-28 18:11:28 +00:00
{
2007-08-22 07:52:33 +00:00
# if defined(CONF_FAMILY_WINDOWS)
2022-03-01 16:34:42 +00:00
ioctlsocket ( sock - > ipv6sock , FIONBIO , ( unsigned long * ) & mode ) ;
2007-08-22 07:52:33 +00:00
# else
2022-03-01 16:34:42 +00:00
if ( ioctl ( sock - > ipv6sock , FIONBIO , ( unsigned long * ) & mode ) = = - 1 )
2019-03-19 10:44:16 +00:00
dbg_msg ( " socket " , " setting ipv6 blocking failed: %d " , errno ) ;
2007-08-22 07:52:33 +00:00
# endif
2011-03-28 18:11:28 +00:00
}
return 0 ;
2007-08-22 07:52:33 +00:00
}
2008-07-06 11:21:21 +00:00
int net_tcp_listen ( NETSOCKET sock , int backlog )
2007-08-22 07:52:33 +00:00
{
2011-07-30 11:40:01 +00:00
int err = - 1 ;
2022-03-01 16:34:42 +00:00
if ( sock - > ipv4sock > = 0 )
err = listen ( sock - > ipv4sock , backlog ) ;
if ( sock - > ipv6sock > = 0 )
err = listen ( sock - > ipv6sock , backlog ) ;
2011-07-30 11:40:01 +00:00
return err ;
2007-08-22 07:52:33 +00:00
}
2008-07-06 11:21:21 +00:00
int net_tcp_accept ( NETSOCKET sock , NETSOCKET * new_sock , NETADDR * a )
2007-08-22 07:52:33 +00:00
{
int s ;
socklen_t sockaddr_len ;
2022-03-01 16:34:42 +00:00
* new_sock = nullptr ;
2011-03-28 18:11:28 +00:00
2022-03-01 16:34:42 +00:00
if ( sock - > ipv4sock > = 0 )
2011-03-28 18:11:28 +00:00
{
2011-07-30 11:40:01 +00:00
struct sockaddr_in addr ;
sockaddr_len = sizeof ( addr ) ;
2007-08-22 07:52:33 +00:00
2022-03-01 16:34:42 +00:00
s = accept ( sock - > ipv4sock , ( struct sockaddr * ) & addr , & sockaddr_len ) ;
2011-08-11 08:59:14 +00:00
2020-09-26 19:41:58 +00:00
if ( s ! = - 1 )
2011-03-28 18:11:28 +00:00
{
2011-07-30 11:40:01 +00:00
sockaddr_to_netaddr ( ( const struct sockaddr * ) & addr , a ) ;
2022-03-01 16:34:42 +00:00
* new_sock = ( NETSOCKET_INTERNAL * ) malloc ( sizeof ( * * new_sock ) ) ;
* * new_sock = invalid_socket ;
( * new_sock ) - > type = NETTYPE_IPV4 ;
( * new_sock ) - > ipv4sock = s ;
2011-03-28 18:11:28 +00:00
return s ;
}
}
2007-08-22 07:52:33 +00:00
2022-03-01 16:34:42 +00:00
if ( sock - > ipv6sock > = 0 )
2007-08-22 07:52:33 +00:00
{
2011-07-30 11:40:01 +00:00
struct sockaddr_in6 addr ;
sockaddr_len = sizeof ( addr ) ;
2011-03-28 18:11:28 +00:00
2022-03-01 16:34:42 +00:00
s = accept ( sock - > ipv6sock , ( struct sockaddr * ) & addr , & sockaddr_len ) ;
2011-08-11 08:59:14 +00:00
2020-09-26 19:41:58 +00:00
if ( s ! = - 1 )
2011-03-28 18:11:28 +00:00
{
2022-03-01 16:34:42 +00:00
* new_sock = ( NETSOCKET_INTERNAL * ) malloc ( sizeof ( * * new_sock ) ) ;
* * new_sock = invalid_socket ;
2011-07-30 11:40:01 +00:00
sockaddr_to_netaddr ( ( const struct sockaddr * ) & addr , a ) ;
2022-03-01 16:34:42 +00:00
( * new_sock ) - > type = NETTYPE_IPV6 ;
( * new_sock ) - > ipv6sock = s ;
2011-03-28 18:11:28 +00:00
return s ;
}
2007-08-22 07:52:33 +00:00
}
2011-03-28 18:11:28 +00:00
2011-07-30 11:40:01 +00:00
return - 1 ;
2007-08-22 07:52:33 +00:00
}
2008-07-06 11:21:21 +00:00
int net_tcp_connect ( NETSOCKET sock , const NETADDR * a )
2007-08-22 07:52:33 +00:00
{
2020-09-26 19:41:58 +00:00
if ( a - > type & NETTYPE_IPV4 )
2011-07-06 16:20:46 +00:00
{
struct sockaddr_in addr ;
netaddr_to_sockaddr_in ( a , & addr ) ;
2022-03-01 16:34:42 +00:00
return connect ( sock - > ipv4sock , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
2011-07-06 16:20:46 +00:00
}
2020-09-26 19:41:58 +00:00
if ( a - > type & NETTYPE_IPV6 )
2011-07-06 16:20:46 +00:00
{
struct sockaddr_in6 addr ;
netaddr_to_sockaddr_in6 ( a , & addr ) ;
2022-03-01 16:34:42 +00:00
return connect ( sock - > ipv6sock , ( struct sockaddr * ) & addr , sizeof ( addr ) ) ;
2011-07-06 16:20:46 +00:00
}
2011-07-30 11:40:01 +00:00
return - 1 ;
2007-08-22 07:52:33 +00:00
}
2011-07-06 16:20:46 +00:00
int net_tcp_connect_non_blocking ( NETSOCKET sock , NETADDR bindaddr )
2007-08-22 07:52:33 +00:00
{
2011-03-28 18:11:28 +00:00
int res = 0 ;
2007-08-22 07:52:33 +00:00
2011-07-06 16:20:46 +00:00
net_set_non_blocking ( sock ) ;
res = net_tcp_connect ( sock , & bindaddr ) ;
net_set_blocking ( sock ) ;
2007-08-22 07:52:33 +00:00
return res ;
}
2008-07-06 11:21:21 +00:00
int net_tcp_send ( NETSOCKET sock , const void * data , int size )
2007-08-22 07:52:33 +00:00
{
2011-07-30 11:40:01 +00:00
int bytes = - 1 ;
2011-07-06 16:20:46 +00:00
2022-03-01 16:34:42 +00:00
if ( sock - > ipv4sock > = 0 )
bytes = send ( ( int ) sock - > ipv4sock , ( const char * ) data , size , 0 ) ;
if ( sock - > ipv6sock > = 0 )
bytes = send ( ( int ) sock - > ipv6sock , ( const char * ) data , size , 0 ) ;
2011-08-11 08:59:14 +00:00
2011-03-28 18:11:28 +00:00
return bytes ;
2007-08-22 07:52:33 +00:00
}
2008-07-06 11:21:21 +00:00
int net_tcp_recv ( NETSOCKET sock , void * data , int maxsize )
2007-08-22 07:52:33 +00:00
{
2011-07-30 11:40:01 +00:00
int bytes = - 1 ;
2011-07-06 16:20:46 +00:00
2022-03-01 16:34:42 +00:00
if ( sock - > ipv4sock > = 0 )
bytes = recv ( ( int ) sock - > ipv4sock , ( char * ) data , maxsize , 0 ) ;
if ( sock - > ipv6sock > = 0 )
bytes = recv ( ( int ) sock - > ipv6sock , ( char * ) data , maxsize , 0 ) ;
2011-08-11 08:59:14 +00:00
2011-03-28 18:11:28 +00:00
return bytes ;
2007-08-22 07:52:33 +00:00
}
2008-07-06 11:21:21 +00:00
int net_tcp_close ( NETSOCKET sock )
2007-08-22 07:52:33 +00:00
{
2011-03-28 18:11:28 +00:00
return priv_net_close_all_sockets ( sock ) ;
2007-08-22 07:52:33 +00:00
}
2021-06-15 02:15:24 +00:00
int net_errno ( )
2007-08-22 07:52:33 +00:00
{
2011-07-30 11:40:01 +00:00
# if defined(CONF_FAMILY_WINDOWS)
return WSAGetLastError ( ) ;
# else
2007-08-22 07:52:33 +00:00
return errno ;
2011-07-30 11:40:01 +00:00
# endif
2007-08-22 07:52:33 +00:00
}
2021-06-15 02:15:24 +00:00
int net_would_block ( )
2007-08-22 07:52:33 +00:00
{
2011-07-30 11:40:01 +00:00
# if defined(CONF_FAMILY_WINDOWS)
return net_errno ( ) = = WSAEWOULDBLOCK ;
# else
2007-08-22 07:52:33 +00:00
return net_errno ( ) = = EWOULDBLOCK ;
2011-07-30 11:40:01 +00:00
# endif
2007-08-22 07:52:33 +00:00
}
2021-06-15 02:15:24 +00:00
int net_init ( )
2007-08-22 07:52:33 +00:00
{
# if defined(CONF_FAMILY_WINDOWS)
WSADATA wsaData ;
int err = WSAStartup ( MAKEWORD ( 1 , 1 ) , & wsaData ) ;
dbg_assert ( err = = 0 , " network initialization failed. " ) ;
2020-09-26 19:41:58 +00:00
return err = = 0 ? 0 : 1 ;
2007-08-22 07:52:33 +00:00
# endif
return 0 ;
}
2017-12-20 15:56:34 +00:00
# if defined(CONF_FAMILY_UNIX)
2021-06-15 02:15:24 +00:00
UNIXSOCKET net_unix_create_unnamed ( )
2017-12-20 15:56:34 +00:00
{
return socket ( AF_UNIX , SOCK_DGRAM , 0 ) ;
}
int net_unix_send ( UNIXSOCKET sock , UNIXSOCKETADDR * addr , void * data , int size )
{
return sendto ( sock , data , size , 0 , ( struct sockaddr * ) addr , sizeof ( struct sockaddr_un ) ) ;
}
void net_unix_set_addr ( UNIXSOCKETADDR * addr , const char * path )
{
2020-11-07 18:57:25 +00:00
mem_zero ( addr , sizeof ( * addr ) ) ;
2017-12-20 15:56:34 +00:00
addr - > sun_family = AF_UNIX ;
str_copy ( addr - > sun_path , path , sizeof ( addr - > sun_path ) ) ;
}
2017-12-20 15:56:44 +00:00
void net_unix_close ( UNIXSOCKET sock )
{
close ( sock ) ;
}
2017-12-20 15:56:34 +00:00
# endif
2021-08-23 13:29:31 +00:00
# if defined(CONF_FAMILY_WINDOWS)
2021-08-23 10:49:15 +00:00
static inline time_t filetime_to_unixtime ( LPFILETIME filetime )
{
time_t t ;
ULARGE_INTEGER li ;
li . LowPart = filetime - > dwLowDateTime ;
li . HighPart = filetime - > dwHighDateTime ;
li . QuadPart / = 10000000 ; // 100ns to 1s
li . QuadPart - = 11644473600LL ; // Windows epoch is in the past
t = li . QuadPart ;
2022-02-18 11:21:48 +00:00
return t = = ( time_t ) li . QuadPart ? t : ( time_t ) - 1 ;
2021-08-23 10:49:15 +00:00
}
# endif
void fs_listdir ( const char * dir , FS_LISTDIR_CALLBACK cb , int type , void * user )
2015-08-27 12:57:56 +00:00
{
# if defined(CONF_FAMILY_WINDOWS)
2021-08-23 10:49:15 +00:00
WIN32_FIND_DATAW finddata ;
2015-08-27 12:57:56 +00:00
HANDLE handle ;
2021-08-23 10:49:15 +00:00
char buffer [ IO_MAX_PATH_LENGTH ] ;
char buffer2 [ IO_MAX_PATH_LENGTH ] ;
WCHAR wBuffer [ IO_MAX_PATH_LENGTH ] ;
2015-08-27 12:57:56 +00:00
int length ;
2021-08-23 10:49:15 +00:00
str_format ( buffer , sizeof ( buffer ) , " %s/* " , dir ) ;
2022-03-30 13:16:19 +00:00
MultiByteToWideChar ( CP_UTF8 , 0 , buffer , - 1 , wBuffer , std : : size ( wBuffer ) ) ;
2015-08-27 12:57:56 +00:00
2021-08-23 10:49:15 +00:00
handle = FindFirstFileW ( wBuffer , & finddata ) ;
2020-09-26 19:41:58 +00:00
if ( handle = = INVALID_HANDLE_VALUE )
2021-08-23 10:49:15 +00:00
return ;
2015-08-27 12:57:56 +00:00
str_format ( buffer , sizeof ( buffer ) , " %s/ " , dir ) ;
length = str_length ( buffer ) ;
/* add all the entries */
do
{
2021-11-21 09:34:11 +00:00
WideCharToMultiByte ( CP_UTF8 , 0 , finddata . cFileName , - 1 , buffer2 , sizeof ( buffer2 ) , NULL , NULL ) ;
2021-08-23 13:29:31 +00:00
str_copy ( buffer + length , buffer2 , ( int ) sizeof ( buffer ) - length ) ;
2022-02-04 15:30:12 +00:00
if ( cb ( buffer2 , ( finddata . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ! = 0 , type , user ) )
2015-08-27 12:57:56 +00:00
break ;
2021-08-23 13:29:31 +00:00
} while ( FindNextFileW ( handle , & finddata ) ) ;
2015-08-27 12:57:56 +00:00
FindClose ( handle ) ;
# else
struct dirent * entry ;
2021-08-23 10:49:15 +00:00
char buffer [ IO_MAX_PATH_LENGTH ] ;
2015-08-27 12:57:56 +00:00
int length ;
DIR * d = opendir ( dir ) ;
if ( ! d )
2021-08-23 10:49:15 +00:00
return ;
2015-08-27 12:57:56 +00:00
str_format ( buffer , sizeof ( buffer ) , " %s/ " , dir ) ;
length = str_length ( buffer ) ;
while ( ( entry = readdir ( d ) ) ! = NULL )
{
2020-09-26 19:41:58 +00:00
str_copy ( buffer + length , entry - > d_name , ( int ) sizeof ( buffer ) - length ) ;
2022-02-04 15:30:12 +00:00
if ( cb ( entry - > d_name , entry - > d_type = = DT_UNKNOWN ? fs_is_dir ( buffer ) : entry - > d_type = = DT_DIR , type , user ) )
2015-08-27 12:57:56 +00:00
break ;
}
/* close the directory and return */
closedir ( d ) ;
# endif
}
2021-08-23 10:49:15 +00:00
void fs_listdir_fileinfo ( const char * dir , FS_LISTDIR_CALLBACK_FILEINFO cb , int type , void * user )
2007-08-22 07:52:33 +00:00
{
# if defined(CONF_FAMILY_WINDOWS)
2021-08-23 10:49:15 +00:00
WIN32_FIND_DATAW finddata ;
2007-08-22 07:52:33 +00:00
HANDLE handle ;
2021-08-23 10:49:15 +00:00
char buffer [ IO_MAX_PATH_LENGTH ] ;
char buffer2 [ IO_MAX_PATH_LENGTH ] ;
WCHAR wBuffer [ IO_MAX_PATH_LENGTH ] ;
2010-09-28 22:53:53 +00:00
int length ;
2007-08-22 07:52:33 +00:00
2021-08-23 10:49:15 +00:00
str_format ( buffer , sizeof ( buffer ) , " %s/* " , dir ) ;
2022-03-30 13:16:19 +00:00
MultiByteToWideChar ( CP_UTF8 , 0 , buffer , - 1 , wBuffer , std : : size ( wBuffer ) ) ;
2007-08-22 07:52:33 +00:00
2021-08-23 10:49:15 +00:00
handle = FindFirstFileW ( wBuffer , & finddata ) ;
2020-09-26 19:41:58 +00:00
if ( handle = = INVALID_HANDLE_VALUE )
2021-08-23 10:49:15 +00:00
return ;
2007-08-22 07:52:33 +00:00
2010-09-28 22:53:53 +00:00
str_format ( buffer , sizeof ( buffer ) , " %s/ " , dir ) ;
length = str_length ( buffer ) ;
2007-08-22 07:52:33 +00:00
/* add all the entries */
do
{
2021-11-21 09:34:11 +00:00
WideCharToMultiByte ( CP_UTF8 , 0 , finddata . cFileName , - 1 , buffer2 , sizeof ( buffer2 ) , NULL , NULL ) ;
2021-08-23 13:29:31 +00:00
str_copy ( buffer + length , buffer2 , ( int ) sizeof ( buffer ) - length ) ;
2021-08-23 10:49:15 +00:00
CFsFileInfo info ;
info . m_pName = buffer2 ;
info . m_TimeCreated = filetime_to_unixtime ( & finddata . ftCreationTime ) ;
info . m_TimeModified = filetime_to_unixtime ( & finddata . ftLastWriteTime ) ;
2022-02-04 15:30:12 +00:00
if ( cb ( & info , ( finddata . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ! = 0 , type , user ) )
2011-02-21 10:23:30 +00:00
break ;
2021-08-23 13:29:31 +00:00
} while ( FindNextFileW ( handle , & finddata ) ) ;
2007-08-22 07:52:33 +00:00
FindClose ( handle ) ;
# else
struct dirent * entry ;
2021-08-23 10:49:15 +00:00
time_t created = - 1 , modified = - 1 ;
char buffer [ IO_MAX_PATH_LENGTH ] ;
2010-09-28 22:53:53 +00:00
int length ;
2007-08-22 07:52:33 +00:00
DIR * d = opendir ( dir ) ;
if ( ! d )
2021-08-23 10:49:15 +00:00
return ;
2011-04-13 18:37:12 +00:00
2010-09-28 22:53:53 +00:00
str_format ( buffer , sizeof ( buffer ) , " %s/ " , dir ) ;
length = str_length ( buffer ) ;
2007-08-22 07:52:33 +00:00
while ( ( entry = readdir ( d ) ) ! = NULL )
2010-09-28 22:53:53 +00:00
{
2021-08-23 10:49:15 +00:00
CFsFileInfo info ;
2020-09-26 19:41:58 +00:00
str_copy ( buffer + length , entry - > d_name , ( int ) sizeof ( buffer ) - length ) ;
2021-08-23 10:49:15 +00:00
fs_file_time ( buffer , & created , & modified ) ;
info . m_pName = entry - > d_name ;
info . m_TimeCreated = created ;
info . m_TimeModified = modified ;
2022-02-04 15:30:12 +00:00
if ( cb ( & info , entry - > d_type = = DT_UNKNOWN ? fs_is_dir ( buffer ) : entry - > d_type = = DT_DIR , type , user ) )
2011-02-21 10:23:30 +00:00
break ;
2010-09-28 22:53:53 +00:00
}
2007-08-22 07:52:33 +00:00
/* close the directory and return */
closedir ( d ) ;
# endif
}
2007-09-25 19:48:52 +00:00
2007-11-08 09:11:32 +00:00
int fs_storage_path ( const char * appname , char * path , int max )
{
# if defined(CONF_FAMILY_WINDOWS)
2021-11-04 19:43:05 +00:00
WCHAR * home = _wgetenv ( L " APPDATA " ) ;
2008-05-10 17:18:56 +00:00
if ( ! home )
2008-08-05 21:37:33 +00:00
return - 1 ;
2021-11-04 19:43:05 +00:00
char buffer [ IO_MAX_PATH_LENGTH ] ;
2021-11-21 09:34:11 +00:00
WideCharToMultiByte ( CP_UTF8 , 0 , home , - 1 , buffer , sizeof ( buffer ) , NULL , NULL ) ;
2021-11-21 09:41:57 +00:00
str_format ( path , max , " %s/%s " , buffer , appname ) ;
2007-11-18 22:06:41 +00:00
return 0 ;
2021-08-24 10:18:20 +00:00
# elif defined(CONF_PLATFORM_ANDROID)
// just use the data directory
return - 1 ;
2007-11-08 09:11:32 +00:00
# else
char * home = getenv ( " HOME " ) ;
if ( ! home )
2008-08-05 21:37:33 +00:00
return - 1 ;
2007-11-18 22:06:41 +00:00
2021-04-17 15:49:41 +00:00
# if defined(CONF_PLATFORM_HAIKU)
str_format ( path , max , " %s/config/settings/%s " , home , appname ) ;
2022-02-01 23:51:40 +00:00
# elif defined(CONF_PLATFORM_MACOS)
2021-11-21 09:41:57 +00:00
str_format ( path , max , " %s/Library/Application Support/%s " , home , appname ) ;
2008-03-22 15:09:49 +00:00
# else
2022-02-01 23:51:40 +00:00
if ( str_comp ( appname , " Teeworlds " ) = = 0 )
{
// fallback for old directory for Teeworlds compatibility
str_format ( path , max , " %s/.%s " , home , appname ) ;
}
else
{
char * data_home = getenv ( " XDG_DATA_HOME " ) ;
if ( data_home )
str_format ( path , max , " %s/%s " , data_home , appname ) ;
else
str_format ( path , max , " %s/.local/share/%s " , home , appname ) ;
}
for ( int i = str_length ( path ) - str_length ( appname ) ; path [ i ] ; i + + )
2020-11-04 18:07:20 +00:00
path [ i ] = tolower ( ( unsigned char ) path [ i ] ) ;
2008-03-22 15:09:49 +00:00
# endif
2011-04-13 18:37:12 +00:00
2008-08-05 21:37:33 +00:00
return 0 ;
2007-11-08 09:11:32 +00:00
# endif
}
2016-05-01 12:20:55 +00:00
int fs_makedir_rec_for ( const char * path )
{
2020-09-26 19:41:58 +00:00
char buffer [ 1024 * 2 ] ;
2016-05-01 12:20:55 +00:00
char * p ;
2016-05-01 17:35:21 +00:00
str_copy ( buffer , path , sizeof ( buffer ) ) ;
2020-09-26 19:41:58 +00:00
for ( p = buffer + 1 ; * p ! = ' \0 ' ; p + + )
2016-05-01 12:20:55 +00:00
{
if ( * p = = ' / ' & & * ( p + 1 ) ! = ' \0 ' )
{
* p = ' \0 ' ;
if ( fs_makedir ( buffer ) < 0 )
return - 1 ;
* p = ' / ' ;
}
}
return 0 ;
}
2007-11-08 09:11:32 +00:00
int fs_makedir ( const char * path )
{
# if defined(CONF_FAMILY_WINDOWS)
2021-11-04 19:43:05 +00:00
WCHAR wBuffer [ IO_MAX_PATH_LENGTH ] ;
2022-03-30 13:16:19 +00:00
MultiByteToWideChar ( CP_UTF8 , 0 , path , - 1 , wBuffer , std : : size ( wBuffer ) ) ;
2021-11-04 19:43:05 +00:00
if ( _wmkdir ( wBuffer ) = = 0 )
2020-09-26 19:41:58 +00:00
return 0 ;
2007-11-18 22:06:41 +00:00
if ( errno = = EEXIST )
return 0 ;
2008-08-05 21:37:33 +00:00
return - 1 ;
2007-11-08 09:11:32 +00:00
# else
2021-04-17 15:49:41 +00:00
# ifdef CONF_PLATFORM_HAIKU
struct stat st ;
if ( stat ( path , & st ) = = 0 )
return 0 ;
# endif
2007-11-08 09:11:32 +00:00
if ( mkdir ( path , 0755 ) = = 0 )
return 0 ;
if ( errno = = EEXIST )
return 0 ;
2008-08-05 21:37:33 +00:00
return - 1 ;
2007-11-08 09:11:32 +00:00
# endif
}
2021-04-21 10:52:27 +00:00
int fs_removedir ( const char * path )
{
# if defined(CONF_FAMILY_WINDOWS)
2021-10-04 18:11:47 +00:00
WCHAR wPath [ IO_MAX_PATH_LENGTH ] ;
2022-03-30 13:16:19 +00:00
MultiByteToWideChar ( CP_UTF8 , 0 , path , - 1 , wPath , std : : size ( wPath ) ) ;
2021-10-04 18:11:47 +00:00
if ( RemoveDirectoryW ( wPath ) ! = 0 )
2021-04-21 10:52:27 +00:00
return 0 ;
return - 1 ;
# else
if ( rmdir ( path ) = = 0 )
return 0 ;
return - 1 ;
# endif
}
2008-10-01 17:16:22 +00:00
int fs_is_dir ( const char * path )
{
# if defined(CONF_FAMILY_WINDOWS)
2021-11-21 09:42:52 +00:00
WCHAR wPath [ IO_MAX_PATH_LENGTH ] ;
2022-03-30 13:16:19 +00:00
MultiByteToWideChar ( CP_UTF8 , 0 , path , - 1 , wPath , std : : size ( wPath ) ) ;
2021-11-21 09:42:52 +00:00
DWORD attributes = GetFileAttributesW ( wPath ) ;
return attributes ! = INVALID_FILE_ATTRIBUTES & & ( attributes & FILE_ATTRIBUTE_DIRECTORY ) ? 1 : 0 ;
2008-10-01 17:16:22 +00:00
# else
struct stat sb ;
2020-09-26 19:41:58 +00:00
if ( stat ( path , & sb ) = = - 1 )
2008-10-01 17:16:22 +00:00
return 0 ;
2021-08-23 10:57:31 +00:00
return S_ISDIR ( sb . st_mode ) ? 1 : 0 ;
2008-10-01 17:16:22 +00:00
# endif
}
int fs_chdir ( const char * path )
{
2010-11-17 17:36:19 +00:00
if ( fs_is_dir ( path ) )
2008-10-01 17:16:22 +00:00
{
2021-11-04 20:31:42 +00:00
# if defined(CONF_FAMILY_WINDOWS)
WCHAR wBuffer [ IO_MAX_PATH_LENGTH ] ;
2022-03-30 13:16:19 +00:00
MultiByteToWideChar ( CP_UTF8 , 0 , path , - 1 , wBuffer , std : : size ( wBuffer ) ) ;
2021-11-04 20:31:42 +00:00
if ( _wchdir ( wBuffer ) )
return 1 ;
else
return 0 ;
# else
2010-11-17 17:36:19 +00:00
if ( chdir ( path ) )
return 1 ;
else
return 0 ;
2021-11-04 20:31:42 +00:00
# endif
2008-10-01 17:16:22 +00:00
}
else
return 1 ;
}
2010-12-11 22:10:13 +00:00
char * fs_getcwd ( char * buffer , int buffer_size )
{
if ( buffer = = 0 )
return 0 ;
# if defined(CONF_FAMILY_WINDOWS)
2021-11-04 20:20:16 +00:00
WCHAR wBuffer [ IO_MAX_PATH_LENGTH ] ;
if ( _wgetcwd ( wBuffer , buffer_size ) = = 0 )
return 0 ;
2021-11-21 09:34:11 +00:00
WideCharToMultiByte ( CP_UTF8 , 0 , wBuffer , - 1 , buffer , buffer_size , NULL , NULL ) ;
2021-11-04 20:20:16 +00:00
return buffer ;
2010-12-11 22:10:13 +00:00
# else
return getcwd ( buffer , buffer_size ) ;
# endif
}
2010-10-07 21:51:07 +00:00
int fs_parent_dir ( char * path )
2010-09-12 11:15:59 +00:00
{
2010-09-16 10:48:32 +00:00
char * parent = 0 ;
for ( ; * path ; + + path )
2010-09-12 11:15:59 +00:00
{
2010-09-16 10:48:32 +00:00
if ( * path = = ' / ' | | * path = = ' \\ ' )
parent = path ;
2010-09-12 11:15:59 +00:00
}
2011-04-13 18:37:12 +00:00
2010-09-16 10:48:32 +00:00
if ( parent )
2010-10-07 21:51:07 +00:00
{
2010-09-16 10:48:32 +00:00
* parent = 0 ;
2010-10-07 21:51:07 +00:00
return 0 ;
}
return 1 ;
2010-09-12 11:15:59 +00:00
}
2010-12-07 23:13:59 +00:00
int fs_remove ( const char * filename )
{
2021-04-21 10:52:27 +00:00
# if defined(CONF_FAMILY_WINDOWS)
2021-10-04 18:11:47 +00:00
WCHAR wFilename [ IO_MAX_PATH_LENGTH ] ;
2022-03-30 13:16:19 +00:00
MultiByteToWideChar ( CP_UTF8 , 0 , filename , - 1 , wFilename , std : : size ( wFilename ) ) ;
2021-10-04 18:11:47 +00:00
return DeleteFileW ( wFilename ) = = 0 ;
2021-04-21 10:52:27 +00:00
# else
return unlink ( filename ) ! = 0 ;
# endif
2010-12-07 23:13:59 +00:00
}
2010-12-07 23:09:18 +00:00
int fs_rename ( const char * oldname , const char * newname )
2015-07-09 00:08:14 +00:00
{
2015-03-14 16:49:18 +00:00
# if defined(CONF_FAMILY_WINDOWS)
2021-10-04 15:49:06 +00:00
WCHAR wOldname [ IO_MAX_PATH_LENGTH ] ;
WCHAR wNewname [ IO_MAX_PATH_LENGTH ] ;
2022-03-30 13:16:19 +00:00
MultiByteToWideChar ( CP_UTF8 , 0 , oldname , - 1 , wOldname , std : : size ( wOldname ) ) ;
MultiByteToWideChar ( CP_UTF8 , 0 , newname , - 1 , wNewname , std : : size ( wNewname ) ) ;
2021-10-04 15:49:06 +00:00
if ( MoveFileExW ( wOldname , wNewname , MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED ) = = 0 )
2015-03-14 16:49:18 +00:00
return 1 ;
# else
2010-12-07 23:09:18 +00:00
if ( rename ( oldname , newname ) ! = 0 )
return 1 ;
2015-03-14 16:49:18 +00:00
# endif
2010-12-07 23:09:18 +00:00
return 0 ;
}
2021-08-23 11:28:50 +00:00
int fs_file_time ( const char * name , time_t * created , time_t * modified )
{
# if defined(CONF_FAMILY_WINDOWS)
WIN32_FIND_DATAW finddata ;
HANDLE handle ;
WCHAR wBuffer [ IO_MAX_PATH_LENGTH ] ;
2022-03-30 13:16:19 +00:00
MultiByteToWideChar ( CP_UTF8 , 0 , name , - 1 , wBuffer , std : : size ( wBuffer ) ) ;
2021-08-23 11:28:50 +00:00
handle = FindFirstFileW ( wBuffer , & finddata ) ;
if ( handle = = INVALID_HANDLE_VALUE )
return 1 ;
* created = filetime_to_unixtime ( & finddata . ftCreationTime ) ;
* modified = filetime_to_unixtime ( & finddata . ftLastWriteTime ) ;
2022-01-18 21:39:20 +00:00
FindClose ( handle ) ;
2021-08-23 11:28:50 +00:00
# elif defined(CONF_FAMILY_UNIX)
struct stat sb ;
if ( stat ( name , & sb ) )
return 1 ;
* created = sb . st_ctime ;
* modified = sb . st_mtime ;
# else
2021-08-23 13:29:31 +00:00
# error not implemented
2021-08-23 11:28:50 +00:00
# endif
return 0 ;
2010-12-07 23:09:18 +00:00
}
2007-09-25 19:48:52 +00:00
void swap_endian ( void * data , unsigned elem_size , unsigned num )
{
2020-09-26 19:41:58 +00:00
char * src = ( char * ) data ;
2007-09-25 19:48:52 +00:00
char * dst = src + ( elem_size - 1 ) ;
while ( num )
{
2020-09-26 19:41:58 +00:00
unsigned n = elem_size > > 1 ;
2007-09-25 19:48:52 +00:00
char tmp ;
while ( n )
{
tmp = * src ;
* src = * dst ;
* dst = tmp ;
src + + ;
dst - - ;
n - - ;
}
2020-09-26 19:41:58 +00:00
src = src + ( elem_size > > 1 ) ;
2007-09-25 19:48:52 +00:00
dst = src + ( elem_size - 1 ) ;
num - - ;
}
}
2007-10-04 09:49:38 +00:00
2008-02-10 15:32:30 +00:00
int net_socket_read_wait ( NETSOCKET sock , int time )
{
2011-04-13 18:37:12 +00:00
struct timeval tv ;
fd_set readfds ;
2011-03-28 18:11:28 +00:00
int sockid ;
2008-02-10 15:32:30 +00:00
2014-11-11 12:00:02 +00:00
tv . tv_sec = time / 1000000 ;
tv . tv_usec = time % 1000000 ;
2011-03-28 18:11:28 +00:00
sockid = 0 ;
2008-02-10 15:32:30 +00:00
2022-01-23 18:04:01 +00:00
FD_ZERO ( & readfds ) ; // NOLINT(clang-analyzer-security.insecureAPI.bzero)
2022-03-01 16:34:42 +00:00
if ( sock - > ipv4sock > = 0 )
2011-03-28 18:11:28 +00:00
{
2022-03-01 16:34:42 +00:00
FD_SET ( sock - > ipv4sock , & readfds ) ;
sockid = sock - > ipv4sock ;
2011-03-28 18:11:28 +00:00
}
2022-03-01 16:34:42 +00:00
if ( sock - > ipv6sock > = 0 )
2011-03-28 18:11:28 +00:00
{
2022-03-01 16:34:42 +00:00
FD_SET ( sock - > ipv6sock , & readfds ) ;
if ( sock - > ipv6sock > sockid )
sockid = sock - > ipv6sock ;
2011-03-28 18:11:28 +00:00
}
2017-03-07 12:03:37 +00:00
# if defined(CONF_WEBSOCKETS)
2022-03-01 16:34:42 +00:00
if ( sock - > web_ipv4sock > = 0 )
2015-02-07 22:15:58 +00:00
{
2022-03-01 16:34:42 +00:00
int maxfd = websocket_fd_set ( sock - > web_ipv4sock , & readfds ) ;
2020-09-18 13:18:31 +00:00
if ( maxfd > sockid )
{
2015-02-07 22:15:58 +00:00
sockid = maxfd ;
2020-09-18 13:18:31 +00:00
FD_SET ( sockid , & readfds ) ;
}
2015-02-07 22:15:58 +00:00
}
# endif
2008-02-10 15:32:30 +00:00
2011-04-13 18:37:12 +00:00
/* don't care about writefds and exceptfds */
2014-01-15 15:52:22 +00:00
if ( time < 0 )
2020-09-26 19:41:58 +00:00
select ( sockid + 1 , & readfds , NULL , NULL , NULL ) ;
2014-01-15 15:52:22 +00:00
else
2020-09-26 19:41:58 +00:00
select ( sockid + 1 , & readfds , NULL , NULL , & tv ) ;
2011-03-28 18:11:28 +00:00
2022-03-01 16:34:42 +00:00
if ( sock - > ipv4sock > = 0 & & FD_ISSET ( sock - > ipv4sock , & readfds ) )
2011-03-28 18:11:28 +00:00
return 1 ;
2020-09-18 13:18:31 +00:00
# if defined(CONF_WEBSOCKETS)
2022-03-01 16:34:42 +00:00
if ( sock - > web_ipv4sock > = 0 & & FD_ISSET ( sockid , & readfds ) )
2020-09-18 13:18:31 +00:00
return 1 ;
# endif
2022-03-01 16:34:42 +00:00
if ( sock - > ipv6sock > = 0 & & FD_ISSET ( sock - > ipv6sock , & readfds ) )
2011-03-28 18:11:28 +00:00
return 1 ;
2011-04-13 18:37:12 +00:00
return 0 ;
2008-02-10 15:32:30 +00:00
}
2021-06-15 02:15:24 +00:00
int time_timestamp ( )
2008-02-10 21:54:52 +00:00
{
return time ( 0 ) ;
}
2021-06-15 02:15:24 +00:00
int time_houroftheday ( )
2020-09-18 16:45:42 +00:00
{
time_t time_data ;
struct tm * time_info ;
time ( & time_data ) ;
time_info = localtime ( & time_data ) ;
return time_info - > tm_hour ;
}
2021-06-15 02:15:24 +00:00
int time_season ( )
2020-09-18 16:45:42 +00:00
{
time_t time_data ;
struct tm * time_info ;
time ( & time_data ) ;
time_info = localtime ( & time_data ) ;
2020-12-28 16:20:29 +00:00
if ( ( time_info - > tm_mon = = 11 & & time_info - > tm_mday = = 31 ) | | ( time_info - > tm_mon = = 0 & & time_info - > tm_mday = = 1 ) )
{
return SEASON_NEWYEAR ;
}
2020-09-18 16:45:42 +00:00
switch ( time_info - > tm_mon )
{
case 11 :
case 0 :
case 1 :
return SEASON_WINTER ;
case 2 :
case 3 :
case 4 :
return SEASON_SPRING ;
case 5 :
case 6 :
case 7 :
return SEASON_SUMMER ;
case 8 :
case 9 :
case 10 :
return SEASON_AUTUMN ;
}
return SEASON_SPRING ; // should never happen
}
2008-02-11 21:49:26 +00:00
void str_append ( char * dst , const char * src , int dst_size )
{
2021-06-05 14:46:01 +00:00
int s = str_length ( dst ) ;
2008-02-11 21:49:26 +00:00
int i = 0 ;
while ( s < dst_size )
{
dst [ s ] = src [ i ] ;
if ( ! src [ i ] ) /* check for null termination */
break ;
s + + ;
i + + ;
}
2011-04-13 18:37:12 +00:00
2020-09-26 19:41:58 +00:00
dst [ dst_size - 1 ] = 0 ; /* assure null termination */
2021-12-20 01:34:02 +00:00
str_utf8_fix_truncation ( dst ) ;
2008-02-11 21:49:26 +00:00
}
void str_copy ( char * dst , const char * src , int dst_size )
{
2022-02-18 11:21:48 +00:00
dst [ 0 ] = ' \0 ' ;
strncat ( dst , src , dst_size - 1 ) ;
2021-12-20 01:34:02 +00:00
str_utf8_fix_truncation ( dst ) ;
2008-02-11 21:49:26 +00:00
}
2020-08-02 11:45:20 +00:00
void str_utf8_truncate ( char * dst , int dst_size , const char * src , int truncation_len )
2019-04-16 00:24:24 +00:00
{
2020-08-02 11:45:20 +00:00
int size = - 1 ;
2021-12-20 01:17:10 +00:00
const char * cursor = src ;
2020-08-10 16:11:51 +00:00
int pos = 0 ;
2021-12-20 01:34:02 +00:00
while ( pos < = truncation_len & & cursor - src < dst_size & & size ! = cursor - src )
2020-08-10 16:11:51 +00:00
{
2021-12-20 01:17:10 +00:00
size = cursor - src ;
if ( str_utf8_decode ( & cursor ) = = 0 )
{
break ;
}
2020-08-10 16:11:51 +00:00
pos + + ;
}
2020-09-26 19:41:58 +00:00
str_copy ( dst , src , size + 1 ) ;
2019-04-16 00:24:24 +00:00
}
2020-09-03 12:08:26 +00:00
void str_truncate ( char * dst , int dst_size , const char * src , int truncation_len )
{
int size = dst_size ;
if ( truncation_len < size )
{
size = truncation_len + 1 ;
}
str_copy ( dst , src , size ) ;
}
2008-11-08 08:27:11 +00:00
int str_length ( const char * str )
{
return ( int ) strlen ( str ) ;
}
2013-07-21 02:52:23 +00:00
int str_format ( char * buffer , int buffer_size , const char * format , . . . )
2008-02-11 21:49:26 +00:00
{
2020-06-29 11:48:51 +00:00
# if defined(CONF_FAMILY_WINDOWS)
2008-02-11 21:49:26 +00:00
va_list ap ;
va_start ( ap , format ) ;
2021-12-20 01:34:02 +00:00
_vsnprintf ( buffer , buffer_size , format , ap ) ;
2020-06-29 11:48:51 +00:00
va_end ( ap ) ;
2019-03-20 18:09:23 +00:00
2020-09-26 19:41:58 +00:00
buffer [ buffer_size - 1 ] = 0 ; /* assure null termination */
2008-02-11 21:49:26 +00:00
# else
2020-06-29 11:48:51 +00:00
va_list ap ;
va_start ( ap , format ) ;
2021-12-20 01:34:02 +00:00
vsnprintf ( buffer , buffer_size , format , ap ) ;
2011-04-13 18:37:12 +00:00
va_end ( ap ) ;
2019-03-20 18:09:23 +00:00
/* null termination is assured by definition of vsnprintf */
2020-06-29 11:48:51 +00:00
# endif
2021-12-20 01:34:02 +00:00
return str_utf8_fix_truncation ( buffer ) ;
2008-02-11 21:49:26 +00:00
}
2015-02-19 21:54:47 +00:00
char * str_trim_words ( char * str , int words )
{
2020-09-26 19:41:58 +00:00
while ( words & & * str )
2015-07-09 00:00:40 +00:00
{
2020-09-26 19:41:58 +00:00
if ( isspace ( * str ) & & ! isspace ( * ( str + 1 ) ) )
2015-07-09 00:00:40 +00:00
words - - ;
str + + ;
}
return str ;
2015-02-19 21:54:47 +00:00
}
2010-08-12 13:22:07 +00:00
/* makes sure that the string only contains the characters between 32 and 255 */
void str_sanitize_cc ( char * str_in )
{
unsigned char * str = ( unsigned char * ) str_in ;
while ( * str )
{
if ( * str < 32 )
* str = ' ' ;
str + + ;
}
}
2008-02-24 16:03:58 +00:00
/* makes sure that the string only contains the characters between 32 and 255 + \r\n\t */
2008-03-17 01:22:25 +00:00
void str_sanitize ( char * str_in )
2008-02-24 16:03:58 +00:00
{
2008-03-17 01:22:25 +00:00
unsigned char * str = ( unsigned char * ) str_in ;
2008-02-24 16:03:58 +00:00
while ( * str )
{
if ( * str < 32 & & ! ( * str = = ' \r ' ) & & ! ( * str = = ' \n ' ) & & ! ( * str = = ' \t ' ) )
* str = ' ' ;
str + + ;
}
}
2017-09-28 13:59:30 +00:00
void str_sanitize_filename ( char * str_in )
{
unsigned char * str = ( unsigned char * ) str_in ;
while ( * str )
{
if ( * str < 32 | | * str = = ' \\ ' | | * str = = ' / ' | | * str = = ' | ' | | * str = = ' : ' | | * str = = ' * ' | | * str = = ' ? ' | | * str = = ' < ' | | * str = = ' > ' | | * str = = ' " ' )
* str = ' ' ;
str + + ;
}
}
2013-09-04 14:44:04 +00:00
/* removes leading and trailing spaces and limits the use of multiple spaces */
void str_clean_whitespaces ( char * str_in )
{
2014-02-28 22:14:18 +00:00
char * read = str_in ;
char * write = str_in ;
/* skip initial whitespace */
while ( * read = = ' ' )
read + + ;
/* end of read string is detected in the loop */
2022-02-14 23:12:52 +00:00
while ( true )
2014-02-28 22:14:18 +00:00
{
/* skip whitespace */
int found_whitespace = 0 ;
for ( ; * read = = ' ' ; read + + )
found_whitespace = 1 ;
/* if not at the end of the string, put a found whitespace here */
if ( * read )
2013-09-04 14:44:04 +00:00
{
2014-02-28 22:14:18 +00:00
if ( found_whitespace )
* write + + = ' ' ;
* write + + = * read + + ;
}
2013-09-08 11:09:41 +00:00
else
2014-02-28 22:14:18 +00:00
{
* write = 0 ;
break ;
}
}
2013-09-04 14:44:04 +00:00
}
2010-10-25 16:41:15 +00:00
char * str_skip_to_whitespace ( char * str )
{
while ( * str & & ( * str ! = ' ' & & * str ! = ' \t ' & & * str ! = ' \n ' ) )
str + + ;
return str ;
}
2020-02-04 16:30:36 +00:00
const char * str_skip_to_whitespace_const ( const char * str )
{
while ( * str & & ( * str ! = ' ' & & * str ! = ' \t ' & & * str ! = ' \n ' ) )
str + + ;
return str ;
}
2010-08-12 13:22:07 +00:00
char * str_skip_whitespaces ( char * str )
{
while ( * str & & ( * str = = ' ' | | * str = = ' \t ' | | * str = = ' \n ' | | * str = = ' \r ' ) )
str + + ;
return str ;
}
2020-02-04 16:30:36 +00:00
const char * str_skip_whitespaces_const ( const char * str )
{
while ( * str & & ( * str = = ' ' | | * str = = ' \t ' | | * str = = ' \n ' | | * str = = ' \r ' ) )
str + + ;
return str ;
}
2008-03-29 17:20:21 +00:00
/* case */
int str_comp_nocase ( const char * a , const char * b )
{
# if defined(CONF_FAMILY_WINDOWS)
2020-09-26 19:41:58 +00:00
return _stricmp ( a , b ) ;
2008-03-29 17:20:21 +00:00
# else
2020-09-26 19:41:58 +00:00
return strcasecmp ( a , b ) ;
2008-03-29 17:20:21 +00:00
# endif
}
2019-01-07 22:49:20 +00:00
int str_comp_nocase_num ( const char * a , const char * b , int num )
2011-06-09 21:28:20 +00:00
{
# if defined(CONF_FAMILY_WINDOWS)
return _strnicmp ( a , b , num ) ;
# else
return strncasecmp ( a , b , num ) ;
# endif
}
2009-06-13 16:54:04 +00:00
int str_comp ( const char * a , const char * b )
{
return strcmp ( a , b ) ;
}
2019-01-07 22:49:20 +00:00
int str_comp_num ( const char * a , const char * b , int num )
2010-05-29 07:25:38 +00:00
{
return strncmp ( a , b , num ) ;
}
2009-06-13 16:54:04 +00:00
2010-09-28 22:53:53 +00:00
int str_comp_filenames ( const char * a , const char * b )
{
int result ;
for ( ; * a & & * b ; + + a , + + b )
{
if ( * a > = ' 0 ' & & * a < = ' 9 ' & & * b > = ' 0 ' & & * b < = ' 9 ' )
{
result = 0 ;
do
{
if ( ! result )
result = * a - * b ;
2020-09-26 19:41:58 +00:00
+ + a ;
+ + b ;
} while ( * a > = ' 0 ' & & * a < = ' 9 ' & & * b > = ' 0 ' & & * b < = ' 9 ' ) ;
2010-09-28 22:53:53 +00:00
if ( * a > = ' 0 ' & & * a < = ' 9 ' )
return 1 ;
else if ( * b > = ' 0 ' & & * b < = ' 9 ' )
return - 1 ;
else if ( result )
return result ;
}
if ( * a ! = * b )
break ;
}
return * a - * b ;
}
2022-03-13 10:42:45 +00:00
const char * str_startswith_nocase ( const char * str , const char * prefix )
{
int prefixl = str_length ( prefix ) ;
if ( str_comp_nocase_num ( str , prefix , prefixl ) = = 0 )
{
return str + prefixl ;
}
else
{
return 0 ;
}
}
2018-07-25 08:23:07 +00:00
const char * str_startswith ( const char * str , const char * prefix )
{
int prefixl = str_length ( prefix ) ;
if ( str_comp_num ( str , prefix , prefixl ) = = 0 )
{
return str + prefixl ;
}
else
{
return 0 ;
}
}
2022-03-13 10:42:45 +00:00
const char * str_endswith_nocase ( const char * str , const char * suffix )
{
int strl = str_length ( str ) ;
int suffixl = str_length ( suffix ) ;
const char * strsuffix ;
if ( strl < suffixl )
{
return 0 ;
}
strsuffix = str + strl - suffixl ;
if ( str_comp_nocase ( strsuffix , suffix ) = = 0 )
{
return strsuffix ;
}
else
{
return 0 ;
}
}
2018-07-26 12:04:44 +00:00
const char * str_endswith ( const char * str , const char * suffix )
2018-07-25 08:23:07 +00:00
{
int strl = str_length ( str ) ;
int suffixl = str_length ( suffix ) ;
2018-07-26 12:04:44 +00:00
const char * strsuffix ;
2018-07-25 08:23:07 +00:00
if ( strl < suffixl )
{
return 0 ;
}
2018-07-26 12:04:44 +00:00
strsuffix = str + strl - suffixl ;
if ( str_comp ( strsuffix , suffix ) = = 0 )
{
return strsuffix ;
}
else
{
return 0 ;
}
2018-07-25 08:23:07 +00:00
}
2018-03-06 17:41:18 +00:00
static int min3 ( int a , int b , int c )
{
int min = a ;
if ( b < min )
min = b ;
if ( c < min )
min = c ;
return min ;
}
int str_utf8_dist ( const char * a , const char * b )
{
int buf_len = 2 * ( str_length ( a ) + 1 + str_length ( b ) + 1 ) ;
2018-04-09 09:56:39 +00:00
int * buf = ( int * ) calloc ( buf_len , sizeof ( * buf ) ) ;
2018-03-06 17:41:18 +00:00
int result = str_utf8_dist_buffer ( a , b , buf , buf_len ) ;
2018-04-09 09:56:39 +00:00
free ( buf ) ;
2018-03-06 17:41:18 +00:00
return result ;
}
static int str_to_utf32_unchecked ( const char * str , int * * out )
{
int out_len = 0 ;
while ( ( * * out = str_utf8_decode ( & str ) ) )
{
( * out ) + + ;
out_len + + ;
}
return out_len ;
}
int str_utf32_dist_buffer ( const int * a , int a_len , const int * b , int b_len , int * buf , int buf_len )
{
int i , j ;
dbg_assert ( buf_len > = ( a_len + 1 ) + ( b_len + 1 ) , " buffer too small " ) ;
if ( a_len > b_len )
{
int tmp1 = a_len ;
const int * tmp2 = a ;
a_len = b_len ;
a = b ;
b_len = tmp1 ;
b = tmp2 ;
}
# define B(i, j) buf[((j)&1) * (a_len + 1) + (i)]
for ( i = 0 ; i < = a_len ; i + + )
{
B ( i , 0 ) = i ;
}
for ( j = 1 ; j < = b_len ; j + + )
{
B ( 0 , j ) = j ;
for ( i = 1 ; i < = a_len ; i + + )
{
int subst = ( a [ i - 1 ] ! = b [ j - 1 ] ) ;
B ( i , j ) = min3 (
B ( i - 1 , j ) + 1 ,
B ( i , j - 1 ) + 1 ,
2020-09-26 19:41:58 +00:00
B ( i - 1 , j - 1 ) + subst ) ;
2018-03-06 17:41:18 +00:00
}
}
return B ( a_len , b_len ) ;
# undef B
}
int str_utf8_dist_buffer ( const char * a_utf8 , const char * b_utf8 , int * buf , int buf_len )
{
int a_utf8_len = str_length ( a_utf8 ) ;
int b_utf8_len = str_length ( b_utf8 ) ;
int * a , * b ; // UTF-32
int a_len , b_len ; // UTF-32 length
dbg_assert ( buf_len > = 2 * ( a_utf8_len + 1 + b_utf8_len + 1 ) , " buffer too small " ) ;
if ( a_utf8_len > b_utf8_len )
{
const char * tmp2 = a_utf8 ;
a_utf8 = b_utf8 ;
b_utf8 = tmp2 ;
}
a = buf ;
a_len = str_to_utf32_unchecked ( a_utf8 , & buf ) ;
b = buf ;
b_len = str_to_utf32_unchecked ( b_utf8 , & buf ) ;
return str_utf32_dist_buffer ( a , a_len , b , b_len , buf , buf_len - b_len - a_len ) ;
}
2008-03-29 17:20:21 +00:00
const char * str_find_nocase ( const char * haystack , const char * needle )
{
while ( * haystack ) /* native implementation */
{
const char * a = haystack ;
const char * b = needle ;
2020-11-04 18:07:20 +00:00
while ( * a & & * b & & tolower ( ( unsigned char ) * a ) = = tolower ( ( unsigned char ) * b ) )
2008-03-29 17:20:21 +00:00
{
a + + ;
b + + ;
}
if ( ! ( * b ) )
return haystack ;
2009-06-13 16:54:04 +00:00
haystack + + ;
}
2011-04-13 18:37:12 +00:00
2009-06-13 16:54:04 +00:00
return 0 ;
}
const char * str_find ( const char * haystack , const char * needle )
{
while ( * haystack ) /* native implementation */
{
const char * a = haystack ;
const char * b = needle ;
while ( * a & & * b & & * a = = * b )
{
a + + ;
b + + ;
}
if ( ! ( * b ) )
return haystack ;
2008-03-29 17:20:21 +00:00
haystack + + ;
}
2011-04-13 18:37:12 +00:00
2008-03-29 17:20:21 +00:00
return 0 ;
}
2019-04-16 00:24:24 +00:00
const char * str_rchr ( const char * haystack , char needle )
{
return strrchr ( haystack , needle ) ;
}
2008-04-05 14:50:43 +00:00
void str_hex ( char * dst , int dst_size , const void * data , int data_size )
{
static const char hex [ ] = " 0123456789ABCDEF " ;
int b ;
2020-09-26 19:41:58 +00:00
for ( b = 0 ; b < data_size & & b < dst_size / 4 - 4 ; b + + )
2008-04-05 14:50:43 +00:00
{
2020-09-26 19:41:58 +00:00
dst [ b * 3 ] = hex [ ( ( const unsigned char * ) data ) [ b ] > > 4 ] ;
dst [ b * 3 + 1 ] = hex [ ( ( const unsigned char * ) data ) [ b ] & 0xf ] ;
dst [ b * 3 + 2 ] = ' ' ;
dst [ b * 3 + 3 ] = 0 ;
2008-04-05 14:50:43 +00:00
}
}
2017-03-02 15:16:29 +00:00
static int hexval ( char x )
{
2020-09-26 19:41:58 +00:00
switch ( x )
{
case ' 0 ' : return 0 ;
case ' 1 ' : return 1 ;
case ' 2 ' : return 2 ;
case ' 3 ' : return 3 ;
case ' 4 ' : return 4 ;
case ' 5 ' : return 5 ;
case ' 6 ' : return 6 ;
case ' 7 ' : return 7 ;
case ' 8 ' : return 8 ;
case ' 9 ' : return 9 ;
case ' a ' :
case ' A ' : return 10 ;
case ' b ' :
case ' B ' : return 11 ;
case ' c ' :
case ' C ' : return 12 ;
case ' d ' :
case ' D ' : return 13 ;
case ' e ' :
case ' E ' : return 14 ;
case ' f ' :
case ' F ' : return 15 ;
default : return - 1 ;
}
2017-03-02 15:16:29 +00:00
}
2017-03-06 11:33:29 +00:00
static int byteval ( const char * byte , unsigned char * dst )
2017-03-02 15:16:29 +00:00
{
2017-03-06 11:33:29 +00:00
int v1 = - 1 , v2 = - 1 ;
v1 = hexval ( byte [ 0 ] ) ;
v2 = hexval ( byte [ 1 ] ) ;
if ( v1 < 0 | | v2 < 0 )
return 1 ;
* dst = v1 * 16 + v2 ;
return 0 ;
2017-03-02 15:16:29 +00:00
}
2018-08-19 10:12:11 +00:00
int str_hex_decode ( void * dst , int dst_size , const char * src )
2017-03-02 15:16:29 +00:00
{
2021-06-15 01:24:23 +00:00
unsigned char * cdst = ( unsigned char * ) dst ;
2018-08-19 10:12:11 +00:00
int slen = str_length ( src ) ;
int len = slen / 2 ;
2017-03-06 19:11:23 +00:00
int i ;
2018-08-19 10:12:11 +00:00
if ( slen ! = dst_size * 2 )
2017-03-06 14:18:52 +00:00
return 2 ;
2017-03-06 11:58:49 +00:00
2017-03-06 19:11:23 +00:00
for ( i = 0 ; i < len & & dst_size ; i + + , dst_size - - )
2017-03-04 20:06:07 +00:00
{
2018-08-19 10:12:11 +00:00
if ( byteval ( src + i * 2 , cdst + + ) )
2017-03-06 11:58:49 +00:00
return 1 ;
2017-03-04 20:06:07 +00:00
}
return 0 ;
2017-03-02 15:16:29 +00:00
}
2021-07-16 00:55:27 +00:00
void str_base64 ( char * dst , int dst_size , const void * data_raw , int data_size )
{
static const char DIGITS [ ] = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ " ;
const unsigned char * data = ( const unsigned char * ) data_raw ;
unsigned value = 0 ;
int num_bits = 0 ;
int i = 0 ;
int o = 0 ;
dst_size - = 1 ;
dst [ dst_size ] = 0 ;
while ( true )
{
if ( num_bits < 6 & & i < data_size )
{
value = ( value < < 8 ) | data [ i ] ;
num_bits + = 8 ;
i + = 1 ;
}
if ( o = = dst_size )
{
return ;
}
if ( num_bits > 0 )
{
unsigned padded ;
if ( num_bits > = 6 )
{
padded = ( value > > ( num_bits - 6 ) ) & 0x3f ;
}
else
{
padded = ( value < < ( 6 - num_bits ) ) & 0x3f ;
}
dst [ o ] = DIGITS [ padded ] ;
num_bits - = 6 ;
o + = 1 ;
}
else if ( o % 4 ! = 0 )
{
dst [ o ] = ' = ' ;
o + = 1 ;
}
else
{
dst [ o ] = 0 ;
return ;
}
}
}
static int base64_digit_value ( char digit )
{
if ( ' A ' < = digit & & digit < = ' Z ' )
{
return digit - ' A ' ;
}
else if ( ' a ' < = digit & & digit < = ' z ' )
{
return digit - ' a ' + 26 ;
}
else if ( ' 0 ' < = digit & & digit < = ' 9 ' )
{
return digit - ' 0 ' + 52 ;
}
else if ( digit = = ' + ' )
{
return 62 ;
}
else if ( digit = = ' / ' )
{
return 63 ;
}
return - 1 ;
}
int str_base64_decode ( void * dst_raw , int dst_size , const char * data )
{
unsigned char * dst = ( unsigned char * ) dst_raw ;
int data_len = str_length ( data ) ;
int i ;
int o = 0 ;
if ( data_len % 4 ! = 0 )
{
return - 3 ;
}
if ( data_len / 4 * 3 > dst_size )
{
// Output buffer too small.
return - 2 ;
}
for ( i = 0 ; i < data_len ; i + = 4 )
{
int num_output_bytes = 3 ;
char copy [ 4 ] ;
int d [ 4 ] ;
int value ;
int b ;
mem_copy ( copy , data + i , sizeof ( copy ) ) ;
if ( i = = data_len - 4 )
{
if ( copy [ 3 ] = = ' = ' )
{
copy [ 3 ] = ' A ' ;
num_output_bytes = 2 ;
if ( copy [ 2 ] = = ' = ' )
{
copy [ 2 ] = ' A ' ;
num_output_bytes = 1 ;
}
}
}
d [ 0 ] = base64_digit_value ( copy [ 0 ] ) ;
d [ 1 ] = base64_digit_value ( copy [ 1 ] ) ;
d [ 2 ] = base64_digit_value ( copy [ 2 ] ) ;
d [ 3 ] = base64_digit_value ( copy [ 3 ] ) ;
if ( d [ 0 ] = = - 1 | | d [ 1 ] = = - 1 | | d [ 2 ] = = - 1 | | d [ 3 ] = = - 1 )
{
// Invalid digit.
return - 1 ;
}
value = ( d [ 0 ] < < 18 ) | ( d [ 1 ] < < 12 ) | ( d [ 2 ] < < 6 ) | d [ 3 ] ;
for ( b = 0 ; b < 3 ; b + + )
{
unsigned char byte_value = ( value > > ( 16 - 8 * b ) ) & 0xff ;
if ( b < num_output_bytes )
{
dst [ o ] = byte_value ;
o + = 1 ;
}
else
{
if ( byte_value ! = 0 )
{
// Padding not zeroed.
return - 2 ;
}
}
}
}
return o ;
}
2017-07-30 10:35:54 +00:00
# ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
# endif
2015-08-27 12:57:56 +00:00
void str_timestamp_ex ( time_t time_data , char * buffer , int buffer_size , const char * format )
2010-12-07 23:26:55 +00:00
{
struct tm * time_info ;
time_info = localtime ( & time_data ) ;
2015-08-27 12:57:56 +00:00
strftime ( buffer , buffer_size , format , time_info ) ;
2020-09-26 19:41:58 +00:00
buffer [ buffer_size - 1 ] = 0 ; /* assure null termination */
2010-12-07 23:26:55 +00:00
}
2017-08-04 20:38:22 +00:00
void str_timestamp_format ( char * buffer , int buffer_size , const char * format )
2015-08-27 12:57:56 +00:00
{
time_t time_data ;
time ( & time_data ) ;
2017-08-04 20:38:22 +00:00
str_timestamp_ex ( time_data , buffer , buffer_size , format ) ;
2015-08-27 12:57:56 +00:00
}
2017-08-04 20:38:22 +00:00
void str_timestamp ( char * buffer , int buffer_size )
{
str_timestamp_format ( buffer , buffer_size , FORMAT_NOSPACE ) ;
}
# ifdef __GNUC__
# pragma GCC diagnostic pop
# endif
2021-06-23 05:05:49 +00:00
int str_time ( int64_t centisecs , int format , char * buffer , int buffer_size )
2020-10-18 20:44:02 +00:00
{
const int sec = 100 ;
const int min = 60 * sec ;
const int hour = 60 * min ;
const int day = 24 * hour ;
if ( buffer_size < = 0 )
return - 1 ;
if ( centisecs < 0 )
centisecs = 0 ;
buffer [ 0 ] = 0 ;
switch ( format )
{
case TIME_DAYS :
if ( centisecs > = day )
2021-06-23 05:05:49 +00:00
return str_format ( buffer , buffer_size , " % " PRId64 " d %02 " PRId64 " :%02 " PRId64 " :%02 " PRId64 , centisecs / day ,
2020-10-18 20:44:02 +00:00
( centisecs % day ) / hour , ( centisecs % hour ) / min , ( centisecs % min ) / sec ) ;
// fall through
case TIME_HOURS :
if ( centisecs > = hour )
2021-06-23 05:05:49 +00:00
return str_format ( buffer , buffer_size , " %02 " PRId64 " :%02 " PRId64 " :%02 " PRId64 , centisecs / hour ,
2020-10-18 20:44:02 +00:00
( centisecs % hour ) / min , ( centisecs % min ) / sec ) ;
// fall through
case TIME_MINS :
2021-06-23 05:05:49 +00:00
return str_format ( buffer , buffer_size , " %02 " PRId64 " :%02 " PRId64 , centisecs / min ,
2020-10-18 20:44:02 +00:00
( centisecs % min ) / sec ) ;
case TIME_HOURS_CENTISECS :
if ( centisecs > = hour )
2021-06-23 05:05:49 +00:00
return str_format ( buffer , buffer_size , " %02 " PRId64 " :%02 " PRId64 " :%02 " PRId64 " .%02 " PRId64 , centisecs / hour ,
2020-10-18 20:44:02 +00:00
( centisecs % hour ) / min , ( centisecs % min ) / sec , centisecs % sec ) ;
// fall through
case TIME_MINS_CENTISECS :
2021-06-23 05:05:49 +00:00
return str_format ( buffer , buffer_size , " %02 " PRId64 " :%02 " PRId64 " .%02 " PRId64 , centisecs / min ,
2020-10-18 20:44:02 +00:00
( centisecs % min ) / sec , centisecs % sec ) ;
}
return - 1 ;
}
int str_time_float ( float secs , int format , char * buffer , int buffer_size )
{
2022-03-21 06:10:44 +00:00
return str_time ( llroundf ( secs * 100 ) , format , buffer , buffer_size ) ;
2020-10-18 20:44:02 +00:00
}
2017-07-08 09:03:51 +00:00
void str_escape ( char * * dst , const char * src , const char * end )
{
2017-07-08 11:06:03 +00:00
while ( * src & & * dst + 1 < end )
2017-07-08 09:03:51 +00:00
{
if ( * src = = ' " ' | | * src = = ' \\ ' ) // escape \ and "
2017-07-08 11:06:03 +00:00
{
if ( * dst + 2 < end )
* ( * dst ) + + = ' \\ ' ;
else
break ;
}
2017-07-08 09:03:51 +00:00
* ( * dst ) + + = * src + + ;
}
2017-07-08 11:06:03 +00:00
* * dst = 0 ;
2017-07-08 09:03:51 +00:00
}
2008-07-06 11:21:21 +00:00
int mem_comp ( const void * a , const void * b , int size )
{
2020-09-26 19:41:58 +00:00
return memcmp ( a , b , size ) ;
2008-07-06 11:21:21 +00:00
}
2022-06-14 18:03:22 +00:00
int mem_has_null ( const void * block , unsigned size )
{
const unsigned char * bytes = ( const unsigned char * ) block ;
unsigned i ;
for ( i = 0 ; i < size ; i + + )
{
if ( bytes [ i ] = = 0 )
{
return 1 ;
}
}
return 0 ;
}
2008-04-05 14:50:43 +00:00
void net_stats ( NETSTATS * stats_inout )
{
* stats_inout = network_stats ;
}
2008-11-08 08:27:11 +00:00
int str_isspace ( char c ) { return c = = ' ' | | c = = ' \n ' | | c = = ' \t ' ; }
2008-09-30 15:52:15 +00:00
2009-06-15 08:15:53 +00:00
char str_uppercase ( char c )
{
if ( c > = ' a ' & & c < = ' z ' )
2020-09-26 19:41:58 +00:00
return ' A ' + ( c - ' a ' ) ;
2009-06-15 08:15:53 +00:00
return c ;
}
2019-02-27 19:24:31 +00:00
int str_isallnum ( const char * str )
{
while ( * str )
{
if ( ! ( * str > = ' 0 ' & & * str < = ' 9 ' ) )
return 0 ;
str + + ;
}
return 1 ;
}
2010-05-29 07:25:38 +00:00
int str_toint ( const char * str ) { return atoi ( str ) ; }
2015-08-20 10:51:30 +00:00
int str_toint_base ( const char * str , int base ) { return strtol ( str , NULL , base ) ; }
2019-05-15 16:11:22 +00:00
unsigned long str_toulong_base ( const char * str , int base ) { return strtoul ( str , NULL , base ) ; }
2010-05-29 07:25:38 +00:00
float str_tofloat ( const char * str ) { return atof ( str ) ; }
2019-01-07 22:49:20 +00:00
int str_utf8_comp_nocase ( const char * a , const char * b )
{
int code_a ;
int code_b ;
while ( * a & & * b )
{
code_a = str_utf8_tolower ( str_utf8_decode ( & a ) ) ;
code_b = str_utf8_tolower ( str_utf8_decode ( & b ) ) ;
if ( code_a ! = code_b )
return code_a - code_b ;
}
return ( unsigned char ) * a - ( unsigned char ) * b ;
}
int str_utf8_comp_nocase_num ( const char * a , const char * b , int num )
{
int code_a ;
int code_b ;
const char * old_a = a ;
2019-02-10 18:20:08 +00:00
if ( num < = 0 )
return 0 ;
2019-01-07 22:49:20 +00:00
while ( * a & & * b )
{
code_a = str_utf8_tolower ( str_utf8_decode ( & a ) ) ;
code_b = str_utf8_tolower ( str_utf8_decode ( & b ) ) ;
if ( code_a ! = code_b )
return code_a - code_b ;
2019-02-10 16:43:00 +00:00
if ( a - old_a > = num )
return 0 ;
2019-01-07 22:49:20 +00:00
}
return ( unsigned char ) * a - ( unsigned char ) * b ;
}
const char * str_utf8_find_nocase ( const char * haystack , const char * needle )
{
while ( * haystack ) /* native implementation */
{
const char * a = haystack ;
const char * b = needle ;
const char * a_next = a ;
const char * b_next = b ;
while ( * a & & * b & & str_utf8_tolower ( str_utf8_decode ( & a_next ) ) = = str_utf8_tolower ( str_utf8_decode ( & b_next ) ) )
{
a = a_next ;
b = b_next ;
}
if ( ! ( * b ) )
return haystack ;
str_utf8_decode ( & haystack ) ;
}
return 0 ;
}
2008-09-30 15:52:15 +00:00
2014-11-08 19:14:12 +00:00
int str_utf8_isspace ( int code )
{
2021-04-01 16:31:55 +00:00
return code < = 0x0020 | | code = = 0x0085 | | code = = 0x00A0 | | code = = 0x034F | |
code = = 0x115F | | code = = 0x1160 | | code = = 0x1680 | | code = = 0x180E | |
2020-09-26 19:41:58 +00:00
( code > = 0x2000 & & code < = 0x200F ) | | ( code > = 0x2028 & & code < = 0x202F ) | |
( code > = 0x205F & & code < = 0x2064 ) | | ( code > = 0x206A & & code < = 0x206F ) | |
2020-10-25 09:17:55 +00:00
code = = 0x2800 | | code = = 0x3000 | | code = = 0x3164 | |
( code > = 0xFE00 & & code < = 0xFE0F ) | | code = = 0xFEFF | | code = = 0xFFA0 | |
2020-09-26 19:41:58 +00:00
( code > = 0xFFF9 & & code < = 0xFFFC ) ;
2014-11-08 19:14:12 +00:00
}
2013-04-26 15:10:05 +00:00
const char * str_utf8_skip_whitespaces ( const char * str )
2013-04-01 18:30:58 +00:00
{
2013-04-26 15:10:05 +00:00
const char * str_old ;
2013-04-01 18:30:58 +00:00
int code ;
while ( * str )
{
str_old = str ;
code = str_utf8_decode ( & str ) ;
// check if unicode is not empty
2018-03-14 01:27:15 +00:00
if ( ! str_utf8_isspace ( code ) )
2013-04-01 18:30:58 +00:00
{
return str_old ;
}
}
return str ;
}
2009-06-13 08:22:37 +00:00
2018-03-14 01:27:15 +00:00
void str_utf8_trim_right ( char * param )
{
const char * str = param ;
char * end = 0 ;
while ( * str )
{
char * str_old = ( char * ) str ;
int code = str_utf8_decode ( & str ) ;
// check if unicode is not empty
if ( ! str_utf8_isspace ( code ) )
{
end = 0 ;
}
else if ( ! end )
{
end = str_old ;
}
}
if ( end )
{
* end = 0 ;
}
}
2015-07-11 17:26:57 +00:00
int str_utf8_isstart ( char c )
2009-06-13 08:22:37 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ( c & 0xC0 ) = = 0x80 ) /* 10xxxxxx */
2009-06-13 08:22:37 +00:00
return 0 ;
return 1 ;
}
int str_utf8_rewind ( const char * str , int cursor )
{
while ( cursor )
{
cursor - - ;
if ( str_utf8_isstart ( * ( str + cursor ) ) )
break ;
}
return cursor ;
}
2021-12-20 01:05:07 +00:00
int str_utf8_fix_truncation ( char * str )
{
int len = str_length ( str ) ;
if ( len > 0 )
{
int last_char_index = str_utf8_rewind ( str , len ) ;
const char * last_char = str + last_char_index ;
// Fix truncated UTF-8.
if ( str_utf8_decode ( & last_char ) = = - 1 )
{
str [ last_char_index ] = 0 ;
return last_char_index ;
}
}
return len ;
}
2009-06-13 08:22:37 +00:00
int str_utf8_forward ( const char * str , int cursor )
{
2021-12-20 01:17:10 +00:00
const char * ptr = str + cursor ;
if ( str_utf8_decode ( & ptr ) = = 0 )
2009-06-13 08:22:37 +00:00
{
2021-12-20 01:17:10 +00:00
return cursor ;
2009-06-13 08:22:37 +00:00
}
2021-12-20 01:17:10 +00:00
return ptr - str ;
2009-06-13 08:22:37 +00:00
}
int str_utf8_encode ( char * ptr , int chr )
{
/* encode */
if ( chr < = 0x7F )
{
ptr [ 0 ] = ( char ) chr ;
return 1 ;
}
else if ( chr < = 0x7FF )
{
2020-09-26 19:41:58 +00:00
ptr [ 0 ] = 0xC0 | ( ( chr > > 6 ) & 0x1F ) ;
ptr [ 1 ] = 0x80 | ( chr & 0x3F ) ;
2009-06-13 08:22:37 +00:00
return 2 ;
}
else if ( chr < = 0xFFFF )
{
2020-09-26 19:41:58 +00:00
ptr [ 0 ] = 0xE0 | ( ( chr > > 12 ) & 0x0F ) ;
ptr [ 1 ] = 0x80 | ( ( chr > > 6 ) & 0x3F ) ;
ptr [ 2 ] = 0x80 | ( chr & 0x3F ) ;
2009-06-13 08:22:37 +00:00
return 3 ;
}
else if ( chr < = 0x10FFFF )
{
2020-09-26 19:41:58 +00:00
ptr [ 0 ] = 0xF0 | ( ( chr > > 18 ) & 0x07 ) ;
ptr [ 1 ] = 0x80 | ( ( chr > > 12 ) & 0x3F ) ;
ptr [ 2 ] = 0x80 | ( ( chr > > 6 ) & 0x3F ) ;
ptr [ 3 ] = 0x80 | ( chr & 0x3F ) ;
2009-06-13 08:22:37 +00:00
return 4 ;
}
2011-04-13 18:37:12 +00:00
2009-06-13 08:22:37 +00:00
return 0 ;
}
2015-06-30 19:09:43 +00:00
static unsigned char str_byte_next ( const char * * ptr )
2009-06-13 08:22:37 +00:00
{
2015-06-30 19:09:43 +00:00
unsigned char byte = * * ptr ;
( * ptr ) + + ;
return byte ;
}
2011-04-13 18:37:12 +00:00
2015-06-30 19:09:43 +00:00
static void str_byte_rewind ( const char * * ptr )
{
( * ptr ) - - ;
}
int str_utf8_decode ( const char * * ptr )
{
// As per https://encoding.spec.whatwg.org/#utf-8-decoder.
unsigned char utf8_lower_boundary = 0x80 ;
unsigned char utf8_upper_boundary = 0xBF ;
int utf8_code_point = 0 ;
int utf8_bytes_seen = 0 ;
int utf8_bytes_needed = 0 ;
2022-02-14 23:12:52 +00:00
while ( true )
2009-06-13 08:22:37 +00:00
{
2015-06-30 19:09:43 +00:00
unsigned char byte = str_byte_next ( ptr ) ;
if ( utf8_bytes_needed = = 0 )
2009-06-13 08:22:37 +00:00
{
2015-08-26 02:02:52 +00:00
if ( byte < = 0x7F )
2015-06-30 19:09:43 +00:00
{
return byte ;
}
2015-09-08 10:44:14 +00:00
else if ( 0xC2 < = byte & & byte < = 0xDF )
2015-06-30 19:09:43 +00:00
{
utf8_bytes_needed = 1 ;
utf8_code_point = byte - 0xC0 ;
}
else if ( 0xE0 < = byte & & byte < = 0xEF )
{
2020-09-26 19:41:58 +00:00
if ( byte = = 0xE0 )
utf8_lower_boundary = 0xA0 ;
if ( byte = = 0xED )
utf8_upper_boundary = 0x9F ;
2015-06-30 19:09:43 +00:00
utf8_bytes_needed = 2 ;
utf8_code_point = byte - 0xE0 ;
}
else if ( 0xF0 < = byte & & byte < = 0xF4 )
{
2020-09-26 19:41:58 +00:00
if ( byte = = 0xF0 )
utf8_lower_boundary = 0x90 ;
if ( byte = = 0xF4 )
utf8_upper_boundary = 0x8F ;
2015-06-30 19:09:43 +00:00
utf8_bytes_needed = 3 ;
utf8_code_point = byte - 0xF0 ;
}
else
{
return - 1 ; // Error.
}
utf8_code_point = utf8_code_point < < ( 6 * utf8_bytes_needed ) ;
continue ;
2009-06-13 08:22:37 +00:00
}
2015-06-30 19:09:43 +00:00
if ( ! ( utf8_lower_boundary < = byte & & byte < = utf8_upper_boundary ) )
2009-06-13 08:22:37 +00:00
{
2015-06-30 19:09:43 +00:00
// Resetting variables not necessary, will be done when
// the function is called again.
str_byte_rewind ( ptr ) ;
return - 1 ;
2009-06-13 08:22:37 +00:00
}
2015-06-30 19:09:43 +00:00
utf8_lower_boundary = 0x80 ;
utf8_upper_boundary = 0xBF ;
utf8_bytes_seen + = 1 ;
utf8_code_point = utf8_code_point + ( ( byte - 0x80 ) < < ( 6 * ( utf8_bytes_needed - utf8_bytes_seen ) ) ) ;
if ( utf8_bytes_seen ! = utf8_bytes_needed )
2009-06-13 08:22:37 +00:00
{
2015-06-30 19:09:43 +00:00
continue ;
2009-06-13 08:22:37 +00:00
}
2015-06-30 19:09:43 +00:00
// Resetting variables not necessary, see above.
return utf8_code_point ;
}
2009-06-13 08:22:37 +00:00
}
2010-09-30 22:55:16 +00:00
int str_utf8_check ( const char * str )
{
2016-01-27 00:48:19 +00:00
int codepoint ;
while ( ( codepoint = str_utf8_decode ( & str ) ) )
2010-09-30 22:55:16 +00:00
{
2016-01-27 00:48:19 +00:00
if ( codepoint = = - 1 )
{
2010-09-30 22:55:16 +00:00
return 0 ;
2016-01-27 00:48:19 +00:00
}
2010-09-30 22:55:16 +00:00
}
return 1 ;
}
2021-11-24 22:24:46 +00:00
void str_utf8_stats ( const char * str , int max_size , int max_count , int * size , int * count )
{
2021-12-20 01:17:10 +00:00
const char * cursor = str ;
2021-11-24 22:24:46 +00:00
* size = 0 ;
* count = 0 ;
2021-11-25 18:54:32 +00:00
while ( * size < max_size & & * count < max_count )
2021-11-24 22:24:46 +00:00
{
2021-12-20 01:17:10 +00:00
if ( str_utf8_decode ( & cursor ) = = 0 )
{
2021-11-25 18:54:32 +00:00
break ;
2021-12-20 01:17:10 +00:00
}
if ( cursor - str > = max_size )
{
break ;
}
* size = cursor - str ;
2021-11-25 18:54:32 +00:00
+ + ( * count ) ;
2021-11-24 22:24:46 +00:00
}
}
2009-06-15 13:01:04 +00:00
unsigned str_quickhash ( const char * str )
{
unsigned hash = 5381 ;
for ( ; * str ; str + + )
hash = ( ( hash < < 5 ) + hash ) + ( * str ) ; /* hash * 33 + c */
return hash ;
}
2019-03-11 11:39:54 +00:00
static const char * str_token_get ( const char * str , const char * delim , int * length )
2019-02-06 12:30:47 +00:00
{
2019-04-29 20:55:12 +00:00
size_t len = strspn ( str , delim ) ;
if ( len > 1 )
str + + ;
else
str + = len ;
2019-02-06 12:30:47 +00:00
if ( ! * str )
return NULL ;
* length = strcspn ( str , delim ) ;
return str ;
}
int str_in_list ( const char * list , const char * delim , const char * needle )
{
const char * tok = list ;
2019-02-13 14:11:09 +00:00
int len = 0 , notfound = 1 , needlelen = str_length ( needle ) ;
2019-02-06 12:30:47 +00:00
2019-03-11 11:39:54 +00:00
while ( notfound & & ( tok = str_token_get ( tok , delim , & len ) ) )
2019-02-13 13:59:46 +00:00
{
2019-02-13 14:11:09 +00:00
notfound = needlelen ! = len | | str_comp_num ( tok , needle , len ) ;
2019-02-06 12:30:47 +00:00
tok = tok + len ;
}
return ! notfound ;
}
2019-03-11 11:39:54 +00:00
const char * str_next_token ( const char * str , const char * delim , char * buffer , int buffer_size )
2019-03-05 09:46:29 +00:00
{
int len = 0 ;
2019-03-11 11:39:54 +00:00
const char * tok = str_token_get ( str , delim , & len ) ;
2020-09-06 14:29:20 +00:00
if ( len < 0 | | tok = = NULL )
{
buffer [ 0 ] = ' \0 ' ;
2019-03-11 11:39:54 +00:00
return NULL ;
2020-09-06 14:29:20 +00:00
}
2019-03-05 09:46:29 +00:00
2019-03-11 11:39:54 +00:00
len = buffer_size > len ? len : buffer_size - 1 ;
mem_copy ( buffer , tok , len ) ;
buffer [ len ] = ' \0 ' ;
2019-03-05 09:46:29 +00:00
2019-03-11 11:39:54 +00:00
return tok + len ;
2019-03-05 09:46:29 +00:00
}
2021-11-08 19:21:02 +00:00
int bytes_be_to_int ( const unsigned char * bytes )
{
2021-12-31 12:18:41 +00:00
int Result ;
unsigned char * pResult = ( unsigned char * ) & Result ;
for ( unsigned i = 0 ; i < sizeof ( int ) ; i + + )
{
# if defined(CONF_ARCH_ENDIAN_BIG)
pResult [ i ] = bytes [ i ] ;
# else
pResult [ i ] = bytes [ sizeof ( int ) - i - 1 ] ;
# endif
}
return Result ;
2021-11-08 19:21:02 +00:00
}
void int_to_bytes_be ( unsigned char * bytes , int value )
{
2021-12-31 12:18:41 +00:00
const unsigned char * pValue = ( const unsigned char * ) & value ;
for ( unsigned i = 0 ; i < sizeof ( int ) ; i + + )
{
# if defined(CONF_ARCH_ENDIAN_BIG)
bytes [ i ] = pValue [ i ] ;
# else
bytes [ sizeof ( int ) - i - 1 ] = pValue [ i ] ;
# endif
}
2021-11-08 19:21:02 +00:00
}
unsigned bytes_be_to_uint ( const unsigned char * bytes )
{
return ( ( bytes [ 0 ] & 0xffu ) < < 24u ) | ( ( bytes [ 1 ] & 0xffu ) < < 16u ) | ( ( bytes [ 2 ] & 0xffu ) < < 8u ) | ( bytes [ 3 ] & 0xffu ) ;
}
void uint_to_bytes_be ( unsigned char * bytes , unsigned value )
{
bytes [ 0 ] = ( value > > 24u ) & 0xffu ;
bytes [ 1 ] = ( value > > 16u ) & 0xffu ;
bytes [ 2 ] = ( value > > 8u ) & 0xffu ;
bytes [ 3 ] = value & 0xffu ;
}
2021-06-15 02:15:24 +00:00
int pid ( )
2014-08-22 12:18:16 +00:00
{
# if defined(CONF_FAMILY_WINDOWS)
return _getpid ( ) ;
# else
return getpid ( ) ;
# endif
}
2021-11-21 17:16:14 +00:00
void cmdline_fix ( int * argc , const char * * * argv )
{
# if defined(CONF_FAMILY_WINDOWS)
int wide_argc = 0 ;
WCHAR * * wide_argv = CommandLineToArgvW ( GetCommandLineW ( ) , & wide_argc ) ;
dbg_assert ( wide_argv ! = NULL , " CommandLineToArgvW failure " ) ;
int total_size = 0 ;
for ( int i = 0 ; i < wide_argc ; i + + )
{
int size = WideCharToMultiByte ( CP_UTF8 , 0 , wide_argv [ i ] , - 1 , NULL , 0 , NULL , NULL ) ;
dbg_assert ( size ! = 0 , " WideCharToMultiByte failure " ) ;
total_size + = size ;
}
char * * new_argv = ( char * * ) malloc ( ( wide_argc + 1 ) * sizeof ( * new_argv ) ) ;
new_argv [ 0 ] = ( char * ) malloc ( total_size ) ;
mem_zero ( new_argv [ 0 ] , total_size ) ;
int remaining_size = total_size ;
for ( int i = 0 ; i < wide_argc ; i + + )
{
int size = WideCharToMultiByte ( CP_UTF8 , 0 , wide_argv [ i ] , - 1 , new_argv [ i ] , remaining_size , NULL , NULL ) ;
dbg_assert ( size ! = 0 , " WideCharToMultiByte failure " ) ;
remaining_size - = size ;
new_argv [ i + 1 ] = new_argv [ i ] + size ;
}
new_argv [ wide_argc ] = 0 ;
* argc = wide_argc ;
* argv = ( const char * * ) new_argv ;
# endif
}
void cmdline_free ( int argc , const char * * argv )
{
# if defined(CONF_FAMILY_WINDOWS)
free ( ( void * ) * argv ) ;
free ( ( char * * ) argv ) ;
# endif
}
2020-09-05 22:38:35 +00:00
PROCESS shell_execute ( const char * file )
2014-12-31 14:07:44 +00:00
{
2015-04-18 12:53:11 +00:00
# if defined(CONF_FAMILY_WINDOWS)
2021-11-20 11:39:52 +00:00
WCHAR wBuffer [ 512 ] ;
2022-03-30 13:16:19 +00:00
MultiByteToWideChar ( CP_UTF8 , 0 , file , - 1 , wBuffer , std : : size ( wBuffer ) ) ;
2021-11-20 11:39:52 +00:00
SHELLEXECUTEINFOW info ;
mem_zero ( & info , sizeof ( SHELLEXECUTEINFOW ) ) ;
info . cbSize = sizeof ( SHELLEXECUTEINFOW ) ;
info . lpVerb = L " open " ;
info . lpFile = wBuffer ;
2021-01-21 08:44:16 +00:00
info . nShow = SW_SHOWMINNOACTIVE ;
2020-09-05 22:38:35 +00:00
info . fMask = SEE_MASK_NOCLOSEPROCESS ;
2021-11-20 11:39:52 +00:00
ShellExecuteExW ( & info ) ;
2020-09-05 22:38:35 +00:00
return info . hProcess ;
2015-04-18 12:53:11 +00:00
# elif defined(CONF_FAMILY_UNIX)
2017-03-07 12:02:37 +00:00
char * argv [ 2 ] ;
pid_t pid ;
2020-09-26 19:41:58 +00:00
argv [ 0 ] = ( char * ) file ;
2015-04-18 12:53:11 +00:00
argv [ 1 ] = NULL ;
2017-03-07 12:02:37 +00:00
pid = fork ( ) ;
2020-09-11 07:47:19 +00:00
if ( pid = = - 1 )
{
return 0 ;
}
if ( pid = = 0 )
{
2015-04-18 12:53:11 +00:00
execv ( file , argv ) ;
2020-09-17 20:19:13 +00:00
_exit ( 1 ) ;
2020-09-11 07:47:19 +00:00
}
2020-09-03 12:08:26 +00:00
return pid ;
# endif
}
2020-09-05 22:38:35 +00:00
int kill_process ( PROCESS process )
2020-09-03 12:08:26 +00:00
{
# if defined(CONF_FAMILY_WINDOWS)
2020-09-05 22:38:35 +00:00
return TerminateProcess ( process , 0 ) ;
2020-09-03 12:08:26 +00:00
# elif defined(CONF_FAMILY_UNIX)
int status ;
2020-09-05 22:38:35 +00:00
kill ( process , SIGTERM ) ;
return ! waitpid ( process , & status , 0 ) ;
2015-04-18 12:53:11 +00:00
# endif
}
2020-06-19 15:04:35 +00:00
int open_link ( const char * link )
{
# if defined(CONF_FAMILY_WINDOWS)
2021-11-20 12:36:05 +00:00
WCHAR wBuffer [ 512 ] ;
2022-03-30 13:16:19 +00:00
MultiByteToWideChar ( CP_UTF8 , 0 , link , - 1 , wBuffer , std : : size ( wBuffer ) ) ;
2021-11-20 12:36:05 +00:00
return ( uintptr_t ) ShellExecuteW ( NULL , L " open " , wBuffer , NULL , NULL , SW_SHOWDEFAULT ) > 32 ;
2020-06-19 15:04:35 +00:00
# elif defined(CONF_PLATFORM_LINUX)
2021-12-19 00:13:08 +00:00
const int pid = fork ( ) ;
if ( pid = = 0 )
execlp ( " xdg-open " , " xdg-open " , link , nullptr ) ;
return pid > 0 ;
2020-06-19 15:04:35 +00:00
# elif defined(CONF_FAMILY_UNIX)
2021-12-19 00:13:08 +00:00
const int pid = fork ( ) ;
if ( pid = = 0 )
execlp ( " open " , " open " , link , nullptr ) ;
return pid > 0 ;
# endif
}
int open_file ( const char * path )
{
# if defined(CONF_PLATFORM_MACOS)
return open_link ( path ) ;
# else
char buf [ 512 ] ;
str_format ( buf , sizeof ( buf ) , " file://%s " , path ) ;
return open_link ( buf ) ;
2020-06-19 15:04:35 +00:00
# endif
}
2015-03-05 23:53:59 +00:00
struct SECURE_RANDOM_DATA
{
int initialized ;
# if defined(CONF_FAMILY_WINDOWS)
HCRYPTPROV provider ;
# else
IOHANDLE urandom ;
# endif
} ;
2020-09-26 19:41:58 +00:00
static struct SECURE_RANDOM_DATA secure_random_data = { 0 } ;
2015-03-05 23:53:59 +00:00
2021-06-15 02:15:24 +00:00
int secure_random_init ( )
2015-03-05 23:53:59 +00:00
{
if ( secure_random_data . initialized )
{
return 0 ;
}
# if defined(CONF_FAMILY_WINDOWS)
2015-03-15 10:59:17 +00:00
if ( CryptAcquireContext ( & secure_random_data . provider , NULL , NULL , PROV_RSA_FULL , CRYPT_VERIFYCONTEXT ) )
2015-03-05 23:53:59 +00:00
{
secure_random_data . initialized = 1 ;
return 0 ;
}
else
{
return 1 ;
}
# else
secure_random_data . urandom = io_open ( " /dev/urandom " , IOFLAG_READ ) ;
if ( secure_random_data . urandom )
{
secure_random_data . initialized = 1 ;
return 0 ;
}
else
{
return 1 ;
}
# endif
}
2022-02-13 19:04:17 +00:00
int secure_random_uninit ( )
{
if ( ! secure_random_data . initialized )
{
return 0 ;
}
# if defined(CONF_FAMILY_WINDOWS)
if ( CryptReleaseContext ( secure_random_data . provider , 0 ) )
{
secure_random_data . initialized = 0 ;
return 0 ;
}
else
{
return 1 ;
}
# else
if ( ! io_close ( secure_random_data . urandom ) )
{
secure_random_data . initialized = 0 ;
return 0 ;
}
else
{
return 1 ;
}
# endif
}
2016-10-01 21:04:16 +00:00
void generate_password ( char * buffer , unsigned length , unsigned short * random , unsigned random_length )
{
static const char VALUES [ ] = " ABCDEFGHKLMNPRSTUVWXYZabcdefghjkmnopqt23456789 " ;
static const size_t NUM_VALUES = sizeof ( VALUES ) - 1 ; // Disregard the '\0'.
2016-10-03 10:31:11 +00:00
unsigned i ;
2016-10-01 21:04:16 +00:00
dbg_assert ( length > = random_length * 2 + 1 , " too small buffer " ) ;
dbg_assert ( NUM_VALUES * NUM_VALUES > = 2048 , " need at least 2048 possibilities for 2-character sequences " ) ;
buffer [ random_length * 2 ] = 0 ;
2016-10-03 10:31:11 +00:00
for ( i = 0 ; i < random_length ; i + + )
2016-10-01 21:04:16 +00:00
{
unsigned short random_number = random [ i ] % 2048 ;
buffer [ 2 * i + 0 ] = VALUES [ random_number / NUM_VALUES ] ;
buffer [ 2 * i + 1 ] = VALUES [ random_number % NUM_VALUES ] ;
}
}
2016-10-06 11:03:48 +00:00
# define MAX_PASSWORD_LENGTH 128
2016-10-01 21:04:16 +00:00
void secure_random_password ( char * buffer , unsigned length , unsigned pw_length )
{
2016-10-03 10:31:11 +00:00
unsigned short random [ MAX_PASSWORD_LENGTH / 2 ] ;
2016-10-01 21:04:16 +00:00
// With 6 characters, we get a password entropy of log(2048) * 6/2 = 33bit.
dbg_assert ( length > = pw_length + 1 , " too small buffer " ) ;
dbg_assert ( pw_length > = 6 , " too small password length " ) ;
dbg_assert ( pw_length % 2 = = 0 , " need an even password length " ) ;
dbg_assert ( pw_length < = MAX_PASSWORD_LENGTH , " too large password length " ) ;
secure_random_fill ( random , pw_length ) ;
generate_password ( buffer , length , random , pw_length / 2 ) ;
}
2016-10-06 11:03:48 +00:00
# undef MAX_PASSWORD_LENGTH
2016-10-01 21:04:16 +00:00
void secure_random_fill ( void * bytes , unsigned length )
2015-03-05 23:53:59 +00:00
{
if ( ! secure_random_data . initialized )
{
dbg_msg ( " secure " , " called secure_random_fill before secure_random_init " ) ;
dbg_break ( ) ;
}
# if defined(CONF_FAMILY_WINDOWS)
2021-06-15 01:24:23 +00:00
if ( ! CryptGenRandom ( secure_random_data . provider , length , ( unsigned char * ) bytes ) )
2015-03-05 23:53:59 +00:00
{
2017-07-30 10:43:54 +00:00
dbg_msg ( " secure " , " CryptGenRandom failed, last_error=%ld " , GetLastError ( ) ) ;
2015-03-05 23:53:59 +00:00
dbg_break ( ) ;
}
# else
if ( length ! = io_read ( secure_random_data . urandom , bytes , length ) )
{
dbg_msg ( " secure " , " io_read returned with a short read " ) ;
dbg_break ( ) ;
}
# endif
}
2021-06-15 02:15:24 +00:00
int secure_rand ( )
2016-01-02 14:37:44 +00:00
{
2016-01-02 14:51:21 +00:00
unsigned int i ;
2016-01-02 14:37:44 +00:00
secure_random_fill ( & i , sizeof ( i ) ) ;
2020-09-26 19:41:58 +00:00
return ( int ) ( i % RAND_MAX ) ;
2016-01-02 14:37:44 +00:00
}
2021-03-13 15:52:35 +00:00
// From https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2.
static unsigned int find_next_power_of_two_minus_one ( unsigned int n )
{
n - - ;
n | = n > > 1 ;
n | = n > > 2 ;
n | = n > > 4 ;
n | = n > > 4 ;
n | = n > > 16 ;
return n ;
}
int secure_rand_below ( int below )
{
unsigned int mask = find_next_power_of_two_minus_one ( below ) ;
dbg_assert ( below > 0 , " below must be positive " ) ;
2022-02-14 23:12:52 +00:00
while ( true )
2021-03-13 15:52:35 +00:00
{
unsigned int n ;
secure_random_fill ( & n , sizeof ( n ) ) ;
n & = mask ;
if ( ( int ) n < below )
{
return n ;
}
}
}
2021-08-26 10:05:36 +00:00
2022-01-27 01:35:08 +00:00
int os_version_str ( char * version , int length )
{
# if defined(CONF_FAMILY_WINDOWS)
const char * DLL = " C: \\ Windows \\ System32 \\ user32.dll " ;
DWORD handle ;
DWORD size = GetFileVersionInfoSizeA ( DLL , & handle ) ;
if ( ! size )
{
return 1 ;
}
void * data = malloc ( size ) ;
if ( ! GetFileVersionInfoA ( DLL , handle , size , data ) )
{
free ( data ) ;
return 1 ;
}
VS_FIXEDFILEINFO * fileinfo ;
UINT unused ;
if ( ! VerQueryValueA ( data , " \\ " , ( void * * ) & fileinfo , & unused ) )
{
free ( data ) ;
return 1 ;
}
str_format ( version , length , " Windows %d.%d.%d.%d " ,
HIWORD ( fileinfo - > dwProductVersionMS ) ,
LOWORD ( fileinfo - > dwProductVersionMS ) ,
HIWORD ( fileinfo - > dwProductVersionLS ) ,
LOWORD ( fileinfo - > dwProductVersionLS ) ) ;
free ( data ) ;
return 0 ;
# else
struct utsname u ;
if ( uname ( & u ) )
{
return 1 ;
}
char extra [ 128 ] ;
extra [ 0 ] = 0 ;
do
{
IOHANDLE os_release = io_open ( " /etc/os-release " , IOFLAG_READ ) ;
char buf [ 4096 ] ;
int read ;
int offset ;
char * newline ;
if ( ! os_release )
{
break ;
}
read = io_read ( os_release , buf , sizeof ( buf ) - 1 ) ;
io_close ( os_release ) ;
buf [ read ] = 0 ;
if ( str_startswith ( buf , " PRETTY_NAME= " ) )
{
offset = 0 ;
}
else
{
const char * found = str_find ( buf , " \n PRETTY_NAME= " ) ;
if ( ! found )
{
break ;
}
offset = found - buf + 1 ;
}
newline = ( char * ) str_find ( buf + offset , " \n " ) ;
if ( newline )
{
* newline = 0 ;
}
str_format ( extra , sizeof ( extra ) , " ; %s " , buf + offset + 12 ) ;
2022-02-14 23:12:52 +00:00
} while ( false ) ;
2022-01-27 01:35:08 +00:00
str_format ( version , length , " %s %s (%s, %s)%s " , u . sysname , u . release , u . machine , u . version , extra ) ;
return 0 ;
# endif
}
2022-02-18 09:46:05 +00:00
# if defined(CONF_EXCEPTION_HANDLING)
# if defined(CONF_FAMILY_WINDOWS)
2022-03-13 18:45:01 +00:00
static HMODULE exception_handling_module = nullptr ;
2022-02-18 09:46:05 +00:00
# endif
void init_exception_handler ( )
{
# if defined(CONF_FAMILY_WINDOWS)
2022-03-13 18:45:01 +00:00
exception_handling_module = LoadLibraryA ( " exchndl.dll " ) ;
if ( exception_handling_module ! = nullptr )
2022-02-18 09:46:05 +00:00
{
2022-02-23 20:10:45 +00:00
// Intentional
# ifdef __MINGW32__
2022-03-21 15:07:46 +00:00
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-function-type"
2022-02-23 20:10:45 +00:00
# endif
2022-03-13 18:45:01 +00:00
auto exc_hndl_init = ( void APIENTRY ( * ) ( void * ) ) GetProcAddress ( exception_handling_module , " ExcHndlInit " ) ;
2022-02-23 20:10:45 +00:00
# ifdef __MINGW32__
2022-03-21 15:07:46 +00:00
# pragma GCC diagnostic pop
2022-02-23 20:10:45 +00:00
# endif
2022-03-13 18:45:01 +00:00
void * exception_handling_offset = ( void * ) GetModuleHandle ( NULL ) ;
exc_hndl_init ( exception_handling_offset ) ;
2022-02-18 09:46:05 +00:00
}
# else
# error exception handling not implemented
# endif
}
2022-03-13 18:45:01 +00:00
void set_exception_handler_log_file ( const char * log_file_path )
2022-02-18 09:46:05 +00:00
{
# if defined(CONF_FAMILY_WINDOWS)
2022-03-13 18:45:01 +00:00
if ( exception_handling_module ! = nullptr )
2022-02-18 09:46:05 +00:00
{
2022-02-18 11:27:15 +00:00
// Intentional
# ifdef __MINGW32__
2022-03-21 15:07:46 +00:00
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-function-type"
2022-02-18 11:27:15 +00:00
# endif
2022-03-13 18:45:01 +00:00
auto exception_log_file_path_func = ( BOOL APIENTRY ( * ) ( const char * ) ) ( GetProcAddress ( exception_handling_module , " ExcHndlSetLogFileNameA " ) ) ;
2022-02-18 11:27:15 +00:00
# ifdef __MINGW32__
2022-03-21 15:07:46 +00:00
# pragma GCC diagnostic pop
2022-02-18 11:27:15 +00:00
# endif
2022-03-13 18:45:01 +00:00
exception_log_file_path_func ( log_file_path ) ;
2022-02-18 09:46:05 +00:00
}
# else
# error exception handling not implemented
# endif
}
# endif
2007-10-04 09:49:38 +00:00
}
2022-05-18 16:00:05 +00:00
2022-06-13 16:07:29 +00:00
std : : chrono : : nanoseconds time_get_nanoseconds ( )
2022-05-18 16:00:05 +00:00
{
2022-06-13 16:07:29 +00:00
return std : : chrono : : nanoseconds ( time_get_impl ( ) ) ;
2022-05-18 16:00:05 +00:00
}
2022-06-13 16:07:29 +00:00
int net_socket_read_wait ( NETSOCKET sock , std : : chrono : : nanoseconds nanoseconds )
2022-05-18 16:00:05 +00:00
{
using namespace std : : chrono_literals ;
return : : net_socket_read_wait ( sock , ( nanoseconds / std : : chrono : : nanoseconds ( 1u s ) . count ( ) ) . count ( ) ) ;
}