2025-03-02 16:15:54 -07:00
#include "server.h"
#include "debug_utility.h"
2025-03-02 16:48:19 -07:00
#include "socket_utility.h"
2025-02-26 20:54:23 -07:00
#include <xtl.h>
#include <winsockx.h>
2025-02-27 09:51:38 -07:00
#include <stdio.h>
2026-01-30 20:01:50 -05:00
#include <string.h>
2025-03-02 16:48:19 -07:00
#include <bearssl.h>
2025-02-26 20:54:23 -07:00
#if !(SERVER_RSA || SERVER_EC || SERVER_MIXED)
#define SERVER_RSA 1
#define SERVER_EC 0
#define SERVER_MIXED 0
#endif
#if SERVER_RSA
#include "chain-rsa.h"
#include "key-rsa.h"
#define SKEY RSA
#elif SERVER_EC
#include "chain-ec.h"
#include "key-ec.h"
#define SKEY EC
#elif SERVER_MIXED
#include "chain-ec+rsa.h"
#include "key-ec.h"
#define SKEY EC
#else
#error Must use one of RSA, EC or MIXED chains.
#endif
2025-03-03 12:21:16 -07:00
#define MAX_NUM_THREADS 5
typedef struct {
int client_socket ;
int thread_complete ;
uint16_t port ;
} thread_info_t ;
typedef struct {
int active ;
thread_info_t data ;
HANDLE thread ;
} pthread_info_t ;
static pthread_info_t threads [ MAX_NUM_THREADS ];
2026-01-30 20:01:50 -05:00
static volatile bool server_running = false ;
static int listen_socket_global = INVALID_SOCKET ;
2025-03-03 12:21:16 -07:00
2025-02-26 20:54:23 -07:00
static const char * HTTP_RES =
2025-03-03 12:21:16 -07:00
"HTTP/1.1 200 OK \r\n "
"Cache-Control: no-store, no-cache, must-revalidate \r\n "
"Pragma: no-cache \r\n "
"Expires: 0 \r\n "
2025-03-02 19:56:46 -07:00
//"Content-Length: 46\r\n"
2025-02-26 20:54:23 -07:00
"Connection: close \r\n "
"Content-Type: text/html; charset=iso-8859-1 \r\n "
" \r\n "
2025-03-02 19:56:46 -07:00
"<head><link rel= \" stylesheet \" href= \" https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css \" ></head>"
2025-02-26 20:54:23 -07:00
"<html> \r\n "
"<body> \r\n "
2025-03-02 19:56:46 -07:00
"<main class= \" container \" ><h1>BearSSL Test by EqUiNoX</h1><a href= \" https://doomonline1.vercel.app/dos.html \" target= \" _blank \" >Play Doom</a></main> \r\n "
2025-02-26 20:54:23 -07:00
"</body> \r\n "
"</html> \r\n " ;
2025-03-03 12:21:16 -07:00
static void client_process ( void * data )
{
thread_info_t * thread_info = ( thread_info_t * ) data ;
unsigned char io_buffer [ BR_SSL_BUFSIZE_BIDI ];
br_ssl_server_context server_context ;
#if SERVER_RSA /* RSA */
#if SERVER_PROFILE_MIN_FS
#if SERVER_CHACHA20
br_ssl_server_init_mine2c ( & server_context , CHAIN , CHAIN_LEN , & SKEY );
#else
br_ssl_server_init_mine2g ( & server_context , CHAIN , CHAIN_LEN , & SKEY );
#endif
#elif SERVER_PROFILE_MIN_NOFS
br_ssl_server_init_minr2g ( & server_context , CHAIN , CHAIN_LEN , & SKEY );
#else
br_ssl_server_init_full_rsa ( & server_context , CHAIN , CHAIN_LEN , & SKEY );
#endif
#elif SERVER_EC /* EC */
#if SERVER_PROFILE_MIN_FS
#if SERVER_CHACHA20
br_ssl_server_init_minf2c ( & server_context , CHAIN , CHAIN_LEN , & SKEY );
#else
br_ssl_server_init_minf2g ( & server_context , CHAIN , CHAIN_LEN , & SKEY );
#endif
#elif SERVER_PROFILE_MIN_NOFS
br_ssl_server_init_minv2g ( & server_context , CHAIN , CHAIN_LEN , & SKEY );
#else
br_ssl_server_init_full_ec ( & server_context , CHAIN , CHAIN_LEN , BR_KEYTYPE_EC , & SKEY );
#endif
#else /* SERVER_MIXED */
#if SERVER_PROFILE_MIN_FS
#if SERVER_CHACHA20
br_ssl_server_init_minf2c ( & server_context , CHAIN , CHAIN_LEN , & SKEY );
#else
br_ssl_server_init_minf2g ( & server_context , CHAIN , CHAIN_LEN , & SKEY );
#endif
#elif SERVER_PROFILE_MIN_NOFS
br_ssl_server_init_minu2g ( & server_context , CHAIN , CHAIN_LEN , & SKEY );
#else
br_ssl_server_init_full_ec ( & server_context , CHAIN , CHAIN_LEN , BR_KEYTYPE_RSA , & SKEY );
#endif
#endif
br_ssl_engine_set_buffer ( & server_context . eng , io_buffer , BR_SSL_BUFSIZE_BIDI , 1 );
br_ssl_server_reset ( & server_context );
br_sslio_context io_context ;
br_sslio_init ( & io_context , & server_context . eng , socket_utility :: socket_read , & thread_info -> client_socket , socket_utility :: socket_write , & thread_info -> client_socket );
bool client_dropped = false ;
int feed_count = 0 ;
while ( true )
{
unsigned char current_char ;
if ( br_sslio_read ( & io_context , & current_char , 1 ) < 0 )
{
client_dropped = true ;
break ;
}
if ( current_char == 0x0D )
{
continue ;
}
if ( current_char == 0x0A )
{
if ( feed_count == 1 )
{
break ;
}
feed_count = 1 ;
}
else
{
feed_count = 0 ;
}
}
if ( client_dropped == false )
{
br_sslio_write_all ( & io_context , HTTP_RES , strlen ( HTTP_RES ));
}
int error = br_ssl_engine_last_error ( & server_context . eng );
if ( error == 0 )
{
debug_utility :: debug_print ( "SSL closed (correctly). \n " );
}
else
{
debug_utility :: debug_print ( "SSL error: %d \n " , error );
}
br_sslio_close ( & io_context );
closesocket ( thread_info -> client_socket );
thread_info -> thread_complete = 1 ;
}
2026-01-30 20:01:50 -05:00
static uint64_t WINAPI process ( void * data )
2025-02-26 20:54:23 -07:00
{
2025-03-02 19:10:14 -07:00
uint16_t port = ( uint16_t ) data ;
2025-02-26 20:54:23 -07:00
2025-03-03 12:21:16 -07:00
int listen_socket = socket_utility :: host_bind ( port );
2026-01-30 20:01:50 -05:00
if ( listen_socket == INVALID_SOCKET )
2025-03-02 19:10:14 -07:00
{
2026-01-30 20:01:50 -05:00
server_running = false ;
2025-02-26 20:54:23 -07:00
return EXIT_FAILURE ;
}
2026-01-30 20:01:50 -05:00
listen_socket_global = listen_socket ;
while ( server_running )
2025-03-02 16:48:19 -07:00
{
2025-03-03 12:21:16 -07:00
int read_status = socket_utility :: get_read_status ( listen_socket );
2025-03-02 19:56:46 -07:00
if ( read_status == SOCKET_ERROR )
{
2026-01-30 20:01:50 -05:00
break ;
2025-03-02 19:56:46 -07:00
}
int client_socket = INVALID_SOCKET ;
if ( read_status == 1 )
{
2025-03-03 12:21:16 -07:00
client_socket = socket_utility :: accept_client ( listen_socket );
2025-03-02 19:56:46 -07:00
}
else
{
2025-03-03 12:21:16 -07:00
Sleep ( 50 );
2025-03-02 19:56:46 -07:00
continue ;
}
2026-01-30 20:01:50 -05:00
if ( client_socket == INVALID_SOCKET )
2025-03-02 19:10:14 -07:00
{
2026-01-30 20:01:50 -05:00
continue ;
2025-02-26 20:54:23 -07:00
}
2025-03-03 12:21:16 -07:00
int i ;
for ( i = 0 ; i < MAX_NUM_THREADS ; i ++ )
2025-03-02 16:48:19 -07:00
{
2025-03-03 12:21:16 -07:00
if ( threads [ i ]. active == 0 )
2025-03-02 19:10:14 -07:00
{
break ;
2025-02-26 20:54:23 -07:00
}
2025-03-03 12:21:16 -07:00
if ( threads [ i ]. data . thread_complete == 1 )
2025-03-02 19:10:14 -07:00
{
2025-03-03 12:21:16 -07:00
CloseHandle ( threads [ i ]. thread );
memset ( & threads [ i ], 0 , sizeof ( pthread_info_t ));
break ;
2025-02-26 20:54:23 -07:00
}
}
2025-03-03 12:21:16 -07:00
if ( i == MAX_NUM_THREADS )
2025-03-02 19:10:14 -07:00
{
2026-01-30 20:01:50 -05:00
closesocket ( client_socket );
2025-03-03 12:21:16 -07:00
continue ;
2025-02-26 20:54:23 -07:00
}
2025-03-02 19:10:14 -07:00
2025-03-03 12:21:16 -07:00
threads [ i ]. active = 1 ;
threads [ i ]. data . client_socket = client_socket ;
threads [ i ]. data . port = port ;
2026-01-30 20:01:50 -05:00
threads [ i ]. thread = CreateThread ( 0 , 0 , ( LPTHREAD_START_ROUTINE ) client_process , ( void * ) & threads [ i ]. data , 0 , NULL );
2025-02-26 20:54:23 -07:00
}
2025-03-02 19:10:14 -07:00
2026-01-30 20:01:50 -05:00
closesocket ( listen_socket );
listen_socket_global = INVALID_SOCKET ;
2025-03-02 19:10:14 -07:00
return 0 ;
}
2025-03-03 12:21:16 -07:00
2026-01-30 20:01:50 -05:00
server :: server ()
: thread ( NULL ), running ( false )
{
}
2025-03-02 19:10:14 -07:00
void server :: start ( uint16_t port )
{
2025-03-03 12:21:16 -07:00
memset ( threads , 0 , sizeof ( threads ));
2026-01-30 20:01:50 -05:00
running = true ;
server_running = true ;
2025-03-02 19:10:14 -07:00
thread = CreateThread ( 0 , 0 , ( LPTHREAD_START_ROUTINE ) process , ( void * ) port , 0 , NULL );
}
void server :: stop ()
{
2026-01-30 20:01:50 -05:00
if ( ! running )
{
return ;
}
running = false ;
server_running = false ;
// Close the listening socket to unblock accept
if ( listen_socket_global != INVALID_SOCKET )
{
closesocket ( listen_socket_global );
}
// Wait for the main server thread to finish
if ( thread != NULL )
{
WaitForSingleObject ( thread , 5000 );
CloseHandle ( thread );
thread = NULL ;
}
// Wait for all client threads to complete
for ( int i = 0 ; i < MAX_NUM_THREADS ; i ++ )
{
if ( threads [ i ]. active && threads [ i ]. thread != NULL )
{
WaitForSingleObject ( threads [ i ]. thread , 2000 );
CloseHandle ( threads [ i ]. thread );
}
}
memset ( threads , 0 , sizeof ( threads ));
}
bool server :: is_running ()
{
return running ;
2025-02-26 20:54:23 -07:00
}
2025-03-02 17:52:32 -07:00