2023-02-21 07:59:09 +01:00
/*
This is part of WHY2
Copyright ( C ) 2022 Václav Š mejkal
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < https : //www.gnu.org/licenses/>.
*/
2023-02-21 07:58:12 +01:00
# include <why2/chat/misc.h>
2023-03-12 14:59:07 +01:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
# include <sys/socket.h>
2023-02-21 10:53:09 +01:00
# include <unistd.h>
2023-02-21 07:58:12 +01:00
2023-03-12 14:59:07 +01:00
# include <pthread.h>
2023-02-21 19:34:40 +01:00
2023-03-24 19:43:48 +01:00
# include <json-c/json.h>
2023-03-12 15:02:06 +01:00
# include <why2/chat/flags.h>
2023-02-21 07:58:12 +01:00
# include <why2/memory.h>
2023-04-01 13:36:08 +02:00
# include <why2/misc.h>
2023-02-21 07:58:12 +01:00
2023-02-21 12:29:45 +01:00
//LINKED LIST STUFF (BIT CHANGED memory.c'S VERSION)
typedef struct node
{
int connection ;
2023-02-22 10:09:58 +01:00
pthread_t thread ;
2023-02-21 12:29:45 +01:00
struct node * next ;
} node_t ; //SINGLE LINKED LIST
node_t * head = NULL ;
2023-02-22 10:09:58 +01:00
void push_to_list ( int connection , pthread_t thread )
2023-02-21 12:29:45 +01:00
{
//CREATE NODE
2023-03-24 19:23:16 +01:00
node_t * new_node = malloc ( sizeof ( node_t ) ) ;
2023-02-21 12:29:45 +01:00
node_t * buffer = head ;
new_node - > connection = connection ;
2023-02-22 10:09:58 +01:00
new_node - > thread = thread ;
2023-02-21 12:29:45 +01:00
new_node - > next = NULL ;
if ( head = = NULL ) //INIT LIST
{
head = new_node ;
} else
{
while ( buffer - > next ! = NULL ) buffer = buffer - > next ; //GET TO THE END OF LIST
buffer - > next = new_node ; //LINK
}
}
void remove_node ( node_t * node )
{
2023-02-21 12:39:54 +01:00
if ( node = = NULL ) return ; //NULL NODE
2023-02-21 12:29:45 +01:00
node_t * buffer_1 = head ;
node_t * buffer_2 ;
while ( buffer_1 - > next ! = NULL ) //GO TROUGH EVERY ELEMENT IN LIST
{
if ( buffer_1 = = node ) break ; //FOUND (IF THE WHILE GOES TROUGH THE WHOLE LIST WITHOUT THE break, I ASSUME THE LAST NODE IS THE CORRECT ONE)
buffer_1 = buffer_1 - > next ;
}
if ( node ! = buffer_1 ) return ; //node WASN'T FOUND
if ( buffer_1 = = head ) //node WAS THE FIRST NODE IN THE LIST
{
//UNLINK
head = buffer_1 - > next ;
} else //wdyt
{
//GET THE NODE BEFORE node
buffer_2 = head ;
while ( buffer_2 - > next ! = buffer_1 ) buffer_2 = buffer_2 - > next ;
//UNLINK
buffer_2 - > next = buffer_1 - > next ;
}
//DEALLOCATION
2023-03-24 19:23:16 +01:00
free ( node ) ;
2023-02-21 12:29:45 +01:00
}
node_t * get_node ( int connection )
{
if ( head = = NULL ) return NULL ; //EMPTY LIST
node_t * buffer = head ;
while ( buffer - > next ! = NULL )
{
if ( buffer - > connection = = connection ) return buffer ;
buffer = buffer - > next ;
}
if ( connection ! = buffer - > connection ) buffer = NULL ; //PREVENT FROM RETURNING INVALID NODE
return buffer ;
}
2023-03-25 17:39:52 +01:00
char * get_string_from_json ( struct json_object * json , char * string )
{
struct json_object * object ;
json_object_object_get_ex ( json , string , & object ) ;
return ( char * ) json_object_get_string ( object ) ;
}
char * get_string_from_json_string ( char * json , char * string )
{
struct json_object * json_obj = json_tokener_parse ( json ) ;
char * returning = get_string_from_json ( json_obj , string ) ;
//DEALLOCATION
json_object_put ( json_obj ) ;
//GET STRINGS
return returning ;
}
void * send_to_all ( void * json )
2023-02-22 12:07:26 +01:00
{
if ( head = = NULL ) return NULL ;
node_t * node_buffer = head ;
2023-03-25 17:39:52 +01:00
//PARSE
struct json_object * json_obj = json_tokener_parse ( ( char * ) json ) ;
2023-03-31 18:12:56 +02:00
if ( json_obj = = NULL ) return NULL ; //EXIT IF INVALID SYNTAX WAS SENT
2023-03-31 17:50:40 +02:00
2023-02-22 12:07:26 +01:00
do //SEND TO ALL CONNECTIONS
{
2023-03-25 17:39:52 +01:00
why2_send_socket ( get_string_from_json ( json_obj , " message " ) , get_string_from_json ( json_obj , " username " ) , node_buffer - > connection ) ; //SEND TO CLIENT
2023-02-22 12:07:26 +01:00
node_buffer = node_buffer - > next ;
} while ( node_buffer - > next ! = NULL ) ;
2023-03-25 17:39:52 +01:00
//DEALLOCATION
json_object_put ( json_obj ) ;
2023-02-22 12:07:26 +01:00
return NULL ;
}
2023-03-24 19:43:48 +01:00
void append ( char * * destination , char * key , char * value )
{
char * output = why2_calloc ( strlen ( * destination ) + strlen ( key ) + strlen ( value ) + 7 , sizeof ( char ) ) ;
sprintf ( output , " %s%s \" %s \" : \" %s \" " , * destination , strcmp ( * destination , " " ) = = 0 ? " " : " , " , key , value ) ;
why2_deallocate ( * destination ) ;
* destination = output ;
}
void add_brackets ( char * * json )
{
char * output = why2_calloc ( strlen ( * json ) + 3 , sizeof ( char ) ) ;
sprintf ( output , " {%s} " , * json ) ;
why2_deallocate ( * json ) ;
* json = output ;
}
2023-03-25 16:35:44 +01:00
char * read_socket_raw ( int socket )
{
if ( socket = = - 1 )
{
fprintf ( stderr , " Reading socket failed. \n " ) ;
return NULL ;
}
unsigned short content_size = 0 ;
char * content_buffer = why2_calloc ( 3 , sizeof ( char ) ) ;
//GET LENGTH
if ( recv ( socket , content_buffer , 2 , 0 ) ! = 2 )
{
fprintf ( stderr , " Getting message length failed! \n " ) ;
return NULL ;
}
content_size = ( unsigned short ) ( ( ( unsigned ) content_buffer [ 1 ] < < 8 ) | content_buffer [ 0 ] ) ;
why2_deallocate ( content_buffer ) ;
//ALLOCATE
content_buffer = why2_calloc ( content_size + 1 , sizeof ( char ) ) ;
//READ JSON MESSAGE
if ( recv ( socket , content_buffer , content_size , 0 ) ! = content_size - 2 ) fprintf ( stderr , " Socket probably read wrongly! \n " ) ;
content_buffer [ content_size - 2 ] = ' \0 ' ; //TODO: Possible problems
return content_buffer ;
}
char * read_socket_from_raw ( char * raw )
{
char * final_message ;
struct json_object * json_obj = json_tokener_parse ( raw ) ;
2023-03-31 18:09:35 +02:00
if ( json_obj = = NULL ) return " ERR " ; //RETURN IF INVALID SYNTAX WAS SENT BY SOME FUCKING SCRIPT KIDDIE
2023-03-25 16:35:44 +01:00
//GET STRINGS
char * message = get_string_from_json ( json_obj , " message " ) ; //TODO: Check deallocation problems
char * username = get_string_from_json ( json_obj , " username " ) ;
//ALLOCATE final_message
final_message = why2_calloc ( strlen ( message ) + strlen ( username ) + 3 , sizeof ( char ) ) ;
//BUILD final_message
sprintf ( final_message , " %s: %s " , username , message ) ;
//DEALLOCATION
json_object_put ( json_obj ) ;
return final_message ;
2023-03-24 20:45:16 +01:00
}
2023-03-31 17:47:05 +02:00
void remove_json_syntax_characters ( char * text )
{
for ( size_t i = 0 ; i < strlen ( text ) ; i + + ) //TODO: DO SOMETHING MORE
{
if ( text [ i ] = = ' \" ' )
{
text [ i ] = ' \' ' ;
}
}
}
2023-02-21 12:29:45 +01:00
//GLOBAL
2023-03-25 17:39:52 +01:00
void why2_send_socket ( char * text , char * username , int socket )
2023-02-21 07:58:12 +01:00
{
2023-03-24 19:43:48 +01:00
char * output = why2_strdup ( " " ) ;
size_t length_buffer = strlen ( text ) ;
char * text_copy = why2_calloc ( length_buffer , sizeof ( char ) ) ;
struct json_object * json = json_tokener_parse ( " {} " ) ;
2023-03-25 17:50:19 +01:00
//COPY text INTO text_copy (WITHOUT LAST CHARACTER WHEN NEWLINE IS AT THE END)
2023-03-31 17:47:05 +02:00
if ( text [ length_buffer - 1 ] = = ' \n ' ) length_buffer - - ;
2023-03-25 17:50:19 +01:00
strncpy ( text_copy , text , length_buffer ) ;
2023-03-24 19:43:48 +01:00
2023-03-31 17:47:05 +02:00
//UNFUCK QUOTES FROM text_copy
remove_json_syntax_characters ( text_copy ) ;
2023-03-24 19:43:48 +01:00
//ADD OBJECTS
json_object_object_add ( json , " message " , json_object_new_string ( text_copy ) ) ;
2023-03-25 17:39:52 +01:00
json_object_object_add ( json , " username " , json_object_new_string ( username ) ) ;
2023-03-24 19:43:48 +01:00
//GENERATE JSON STRING
json_object_object_foreach ( json , key , value )
{
append ( & output , key , ( char * ) json_object_get_string ( value ) ) ;
}
add_brackets ( & output ) ;
why2_deallocate ( text_copy ) ;
json_object_put ( json ) ;
//printf("NEGR\n");
unsigned short text_length = ( unsigned short ) strlen ( output ) + 2 ;
2023-02-21 19:19:47 +01:00
char * final = why2_calloc ( text_length , sizeof ( char ) ) ;
2023-02-21 07:58:12 +01:00
//SPLIT LENGTH INTO TWO CHARS
final [ 0 ] = ( unsigned ) text_length & 0xff ;
final [ 1 ] = ( unsigned ) text_length > > 8 ;
2023-02-21 19:19:47 +01:00
for ( int i = 2 ; i < text_length ; i + + ) //APPEND
2023-02-21 07:58:12 +01:00
{
2023-03-24 19:43:48 +01:00
final [ i ] = output [ i - 2 ] ;
2023-02-21 07:58:12 +01:00
}
//SEND
2023-02-21 19:48:28 +01:00
send ( socket , final , text_length , 0 ) ;
2023-02-21 07:58:12 +01:00
2023-03-24 19:43:48 +01:00
//DEALLOCATION
2023-02-21 07:58:12 +01:00
why2_deallocate ( final ) ;
2023-03-24 19:43:48 +01:00
why2_deallocate ( output ) ;
2023-02-21 10:53:09 +01:00
}
2023-02-21 12:33:33 +01:00
void * why2_communicate_thread ( void * arg )
2023-02-21 10:53:09 +01:00
{
2023-04-01 12:43:49 +02:00
int connection = * ( int * ) arg ;
2023-02-22 10:09:58 +01:00
2023-04-01 12:43:49 +02:00
printf ( " User connected. \t %d \n " , connection ) ;
2023-02-21 10:53:09 +01:00
2023-04-01 12:43:49 +02:00
push_to_list ( connection , pthread_self ( ) ) ; //ADD TO LIST
2023-02-21 18:59:44 +01:00
2023-04-01 13:36:08 +02:00
time_t start_time = time ( NULL ) ;
2023-02-21 10:53:09 +01:00
char * received = NULL ;
2023-03-25 16:37:58 +01:00
char * raw = NULL ;
char * decoded_buffer ;
2023-02-22 12:07:26 +01:00
pthread_t thread_buffer ;
2023-04-01 13:36:08 +02:00
why2_bool exiting = 0 ;
2023-02-21 10:53:09 +01:00
2023-04-01 13:46:02 +02:00
while ( ( time ( NULL ) - start_time ) < WHY2_COMMUNICATION_TIME & & ! exiting ) //KEEP COMMUNICATION ALIVE FOR 5 MINUTES [RESET TIMER AT MESSAGE SENT] //TODO: Fix stuck
2023-02-21 10:53:09 +01:00
{
2023-03-25 16:37:58 +01:00
//READ
2023-04-01 12:43:49 +02:00
raw = read_socket_raw ( connection ) ;
2023-03-31 18:21:06 +02:00
2023-03-31 18:36:09 +02:00
if ( raw = = NULL ) break ; //QUIT COMMUNICATION IF INVALID PACKET WAS RECEIVED
2023-03-31 18:21:06 +02:00
//REMOVE CONTROL CHARACTERS FROM raw
for ( size_t i = 0 ; i < strlen ( raw ) ; i + + )
{
if ( raw [ i ] = = ' \\ ' ) raw [ i ] = ' / ' ;
}
2023-03-25 16:37:58 +01:00
received = read_socket_from_raw ( raw ) ;
2023-02-21 10:53:09 +01:00
2023-04-01 12:49:26 +02:00
if ( received = = NULL ) break ; //FAILED; EXIT THREAD
2023-02-21 10:53:09 +01:00
2023-03-25 16:37:58 +01:00
decoded_buffer = get_string_from_json_string ( raw , " message " ) ; //DECODE
if ( decoded_buffer [ 0 ] = = ' ! ' ) //COMMANDS
2023-02-23 09:05:16 +01:00
{
2023-04-01 13:36:08 +02:00
if ( strcmp ( decoded_buffer , " !exit " ) = = 0 ) exiting = 1 ; //USER REQUESTED EXIT
2023-02-23 09:05:16 +01:00
2023-04-01 13:36:08 +02:00
goto deallocation ; //IGNORE MESSAGES BEGINNING WITH '!'
2023-02-23 09:05:16 +01:00
}
2023-02-21 10:53:09 +01:00
printf ( " Received: \n %s \n \n " , received ) ;
2023-03-25 17:39:52 +01:00
pthread_create ( & thread_buffer , NULL , send_to_all , raw ) ;
2023-02-22 14:37:18 +01:00
pthread_join ( thread_buffer , NULL ) ;
2023-02-22 12:07:26 +01:00
2023-04-01 13:36:08 +02:00
//RESET TIMER
start_time = time ( NULL ) ;
deallocation :
2023-02-21 10:53:09 +01:00
why2_deallocate ( received ) ;
2023-03-25 16:37:58 +01:00
why2_deallocate ( raw ) ;
why2_deallocate ( decoded_buffer ) ;
2023-02-21 10:53:09 +01:00
}
2023-04-01 12:43:49 +02:00
printf ( " User exited. \t %d \n " , connection ) ;
2023-02-21 10:53:09 +01:00
//DEALLOCATION
why2_deallocate ( received ) ;
2023-04-01 12:43:49 +02:00
close ( connection ) ;
remove_node ( get_node ( connection ) ) ;
2023-02-21 10:53:09 +01:00
return NULL ;
}
2023-02-21 12:33:33 +01:00
char * why2_read_socket ( int socket )
2023-02-21 10:53:09 +01:00
{
2023-03-25 16:37:42 +01:00
char * raw_socket = read_socket_raw ( socket ) ;
2023-03-24 20:01:15 +01:00
char * final_message ;
2023-03-25 16:37:42 +01:00
struct json_object * json_obj = json_tokener_parse ( raw_socket ) ;
2023-03-24 20:01:15 +01:00
//GET STRINGS
2023-03-24 20:45:16 +01:00
char * message = get_string_from_json ( json_obj , " message " ) ; //TODO: Check deallocation problems
char * username = get_string_from_json ( json_obj , " username " ) ;
2023-03-24 20:01:15 +01:00
2023-03-25 16:37:42 +01:00
//ALLOCATE final_message
2023-03-24 20:01:15 +01:00
final_message = why2_calloc ( strlen ( message ) + strlen ( username ) + 3 , sizeof ( char ) ) ;
//BUILD final_message
sprintf ( final_message , " %s: %s " , username , message ) ;
//DEALLOCATION
2023-03-25 16:37:42 +01:00
why2_deallocate ( raw_socket ) ;
2023-03-24 20:01:15 +01:00
json_object_put ( json_obj ) ;
return final_message ;
2023-02-21 10:53:09 +01:00
}
2023-02-21 12:31:27 +01:00
2023-02-21 19:34:40 +01:00
void * why2_accept_thread ( void * socket )
{
int accepted ;
pthread_t thread ;
//LOOP ACCEPT
for ( ; ; )
{
2023-03-12 15:01:04 +01:00
accepted = accept ( * ( ( int * ) socket ) , ( WHY2_SA * ) NULL , NULL ) ; //ACCEPT NEW SOCKET //TODO: CLOSE (not only this one)
2023-02-21 19:34:40 +01:00
if ( accepted = = - 1 ) continue ;
2023-04-01 12:43:49 +02:00
pthread_create ( & thread , NULL , why2_communicate_thread , & accepted ) ;
2023-02-21 19:34:40 +01:00
}
2023-02-22 10:16:01 +01:00
}
void why2_clean_threads ( void )
{
if ( head = = NULL ) return ; //EMPTY LIST
node_t * node_buffer = head ;
node_t * node_buffer_2 ;
while ( node_buffer - > next ! = NULL ) //GO TROUGH LIST
{
node_buffer_2 = node_buffer ;
node_buffer = node_buffer - > next ;
2023-02-22 10:19:36 +01:00
close ( node_buffer_2 - > connection ) ;
pthread_cancel ( node_buffer_2 - > thread ) ;
2023-02-22 10:16:01 +01:00
remove_node ( node_buffer_2 ) ; //REMOVE
}
2023-02-22 12:12:04 +01:00
}
void * why2_listen_server ( void * socket )
{
2023-02-24 16:31:20 +01:00
char * read = NULL ;
printf ( " >>> " ) ; //TODO: Make this smart
fflush ( stdout ) ;
2023-02-22 12:12:04 +01:00
for ( ; ; )
{
2023-02-24 16:31:20 +01:00
read = why2_read_socket ( * ( ( int * ) socket ) ) ; //TODO: Fix other user message formatting
2023-03-12 15:01:04 +01:00
printf ( WHY2_CLEAR_AND_GO_UP ) ;
2023-03-24 20:18:44 +01:00
printf ( " %s \n \n >>> " , read ) ; //TODO: wtf is the output
2023-02-24 16:31:20 +01:00
fflush ( stdout ) ;
why2_deallocate ( read ) ;
2023-02-22 12:12:04 +01:00
}
2023-03-24 20:18:44 +01:00
}
//BUG: SERVER SOMETIMES CRASHES - I HAVE NO FUCKING IDEA WHY