diff options
author | scratko <m@scratko.xyz> | 2024-08-30 12:46:56 +0300 |
---|---|---|
committer | scratko <m@scratko.xyz> | 2024-08-30 14:59:44 +0300 |
commit | 831f9f01fbe4088eb6bd378c0e417d9996b676fd (patch) | |
tree | 53297459d35ad795618c351a79b1829776e5e1f4 /linux_client/client.c | |
parent | 4b6c15f780d59895f067383a5041edcfe86f504e (diff) | |
download | durak-831f9f01fbe4088eb6bd378c0e417d9996b676fd.tar.gz durak-831f9f01fbe4088eb6bd378c0e417d9996b676fd.tar.bz2 durak-831f9f01fbe4088eb6bd378c0e417d9996b676fd.zip |
Final version v2.0
Added windows client.
SIGPIPE signal was being sent to the server when the client was disconnected.
Now there is handling of this signal.
Added a delay when displaying some informational messages.
Diffstat (limited to 'linux_client/client.c')
-rw-r--r-- | linux_client/client.c | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/linux_client/client.c b/linux_client/client.c new file mode 100644 index 0000000..2115b98 --- /dev/null +++ b/linux_client/client.c @@ -0,0 +1,321 @@ +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> /* for debug */ + +#include "client.h" +#include "data_decryption.h" +#include "printing_game_frames.h" +#include "verification_client_input.h" + +static const char *ip = "109.107.161.30"; +static const int port = 1025; + +static void clean_up_resources(struct client *cl) +{ + free(cl->cc.number_arr); + clear_stack(&cl->deck); +} + +static void get_data_from_server(struct client *cl, fd_set *readfds) +{ + int i; + int update_info = 0; + /* pointer to delimeter (:) that is behind extract data */ + char *end_p; + + if(FD_ISSET(cl->fd, readfds)) { + if(!cl->data_left_in_buffer) { + cl->data_left_in_buffer = read(cl->fd, cl->buffer, max_buffer_size); + /* end of file -- closed connection (from server) */ + if(!cl->data_left_in_buffer) { + clean_up_resources(cl); + exit(0); + } +#ifdef DEBUG + printf("%d\n", cl->data_left_in_buffer); + for(i = 0; i < cl->data_left_in_buffer; ++i) + putchar(cl->buffer[i]); + putchar('\n'); +#endif + } + decrypt_set_state(cl, &end_p); + update_info = 1; + cl->display_new_frame = 1; + cl->pending_server_response = 0; + } + if(update_info) { + switch(cl->state) { + case first_player: + break; + case confirmation_waiting: + cl->total_players = decrypt_get_number(end_p+1, &end_p); + break; + case display_only_table: + case tossing_expectation: + case tossing: + /* last arg will contain pointer to '\n' */ + decrypt_set_base_info(cl, end_p+1, &end_p); + break; + case attack: + case defense: + case attack_expectation: + decrypt_set_base_info(cl, end_p+1, &end_p); + decrypt_set_position_whose_turn(cl, end_p+1, &end_p); + break; + case defense_expectation: + case spectator: + decrypt_set_base_info(cl, end_p+1, &end_p); + decrypt_set_position_whose_turn(cl, end_p+1, &end_p); + decrypt_set_card_queue(cl, end_p+1, &end_p); + if(cl->state == spectator) + decrypt_set_spectator_mode(cl, end_p+1); + break; + case card_acceptance_status: + decrypt_set_card_acceptance_status(cl, end_p+1); + break; + case result: + decrypt_set_durak_position(cl, end_p+1); + break; + /* no data to extract */ + case tossing_limit_status: + case disconnect: + default: + {} + } + for(i = 0; cl->buffer[i] != '\n'; ++i) + {} + if((cl->buffer+i - cl->buffer + 1) != cl->data_left_in_buffer) { + cl->data_left_in_buffer -= i + 1; + memmove(cl->buffer, cl->buffer+i+1, cl->data_left_in_buffer); + } else + cl->data_left_in_buffer = 0; + } +} + +static void prepare_tips_for_client(struct client *cl) +{ + char *trump_suit = NULL; + + if(!is_empty_stack(cl->deck)) + add_hint_letters_stack(cl->deck); + switch(cl->state) { + case attack: + mark_card_for_attackers_stack(cl->deck); + break; + case defense: + trump_suit = cl->trump_card + strlen(cl->trump_card) - 1; + mark_card_for_defenders_stack(cl->deck, &cl->cot, trump_suit); + break; + case tossing: + mark_card_for_tossing_stack(cl->deck, &cl->cot); + break; + default: + {} + } +} + +static void change_client_frame(struct client *cl) +{ + if(cl->display_new_frame) { + pgf_new_frame(); + switch(cl->state) { + case first_player: + pgf_first_player(); + break; + case confirmation_waiting: + pgf_confirmation_waiting(cl->total_players); + break; + case display_only_table: + case attack_expectation: + case defense_expectation: + case tossing_expectation: + pgf_table(cl); + if(cl->state == attack_expectation || + cl->state == defense_expectation || + cl->state == tossing_expectation) + { + pgf_select_idle_mode_message(cl->state); + } + break; + case spectator: + pgf_table(cl); + pgf_spectator_mode(cl->sp_mode); + break; + case attack: + case defense: + case tossing: + pgf_table(cl); + pgf_suggestions(cl); + break; + case card_acceptance_status: + pgf_card_acceptance_status(cl->all_input_cards_accepted); + break; + case tossing_limit_status: + pgf_tossing_limit_status(); + break; + case result: + pgf_game_result(cl->durak_position); + break; + case disconnect: + pgf_disconnect(); + break; + case none: + {} + } + cl->display_new_frame = 0; + } +} + +static int check_users_exit(enum client_states state, const char *buffer, + int size) +{ + if((state == first_player || state == confirmation_waiting) && + size == 2 && (buffer[0] == 'q' && buffer[1] == '\n')) + return 1; + + return size == 3 && !strncmp(buffer, "qq", 2) && buffer[2] == '\n'; +} + +static void send_data_to_server(struct client *cl, fd_set *readfds) +{ + int input_result = 0, data_size; + + if(FD_ISSET(0, readfds)) { /* 0 - stdin */ + data_size = read(0, cl->buffer, max_buffer_size); + if(check_users_exit(cl->state, cl->buffer, data_size)) { + close(cl->fd); + clean_up_resources(cl); + pgf_disconnect(); + exit(0); + } + + switch(cl->state) { + case confirmation_waiting: + input_result = vci_confirmation_waiting(cl->fd, cl->buffer); + break; + case attack: + case tossing: + input_result = vci_attack_or_tossing(cl->fd, cl->buffer, cl->deck, + cl->state); + break; + case defense: + input_result = vci_defense(cl->fd, cl->buffer, cl->deck); + break; + default: + {} + } + /* if 0, then re-tracking the input client */ + if(input_result) + cl->pending_server_response = 1; + } +} + +static int check_tracking_client_input(enum client_states state, + int pending_server_response) +{ + if(pending_server_response) + return 0; + + switch(state) { + case first_player: + case confirmation_waiting: + case attack: + case defense: + case tossing: + return 1; + default: + return 0; + } + return 0; +} + +int main_loop(struct client *cl) +{ + int select_result; + fd_set readfds; + + for(;;) { + FD_ZERO(&readfds); + + FD_SET(cl->fd, &readfds); + if(check_tracking_client_input(cl->state, cl->pending_server_response)) + FD_SET(0, &readfds); + + if(!cl->data_left_in_buffer) { + select_result = select(cl->fd + 1, &readfds, NULL, NULL, NULL); + if(select_result == -1) + return 2; + } + get_data_from_server(cl, &readfds); + prepare_tips_for_client(cl); + if(cl->display_new_frame) + change_client_frame(cl); + send_data_to_server(cl, &readfds); + } +} + +static void init_client(struct client *cl) +{ + cl->fd = -1; + cl->state = none; + cl->total_players = 0; + cl->total_cards_left = 0; + cl->player_position = 0; + cl->cc.number_arr = NULL; + cl->cc.number_arr_idx = -1; + cl->cot.card_arr_idx = -1; + cl->deck = NULL; + cl->pending_server_response = 0; + cl->cq.card_arr_idx = -1; + cl->position_whose_turn = 0; + cl->display_new_frame = 0; + cl->all_input_cards_accepted = 0; + cl->data_left_in_buffer = 0; + cl->sp_mode = spectator_table; + cl->durak_position = 0; +} + +/* + * 0 - failure + * 1 - success + */ +static int connect_to_server(struct client *cl) +{ + int connect_result; + struct sockaddr_in addr; + + cl->fd = socket(AF_INET, SOCK_STREAM, 0); + + if(cl->fd == -1) + return 0; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(ip); + addr.sin_port = htons(port); + + connect_result = connect(cl->fd, (struct sockaddr*) &addr, sizeof(addr)); + if(connect_result == -1) + return 0; + return 1; +} + +int main() +{ + struct client cl; + + pgf_new_frame(); + pgf_welcome(); + sleep(2); + init_client(&cl); + if(!connect_to_server(&cl)) { + pgf_new_frame(); + pgf_connection(0); + return 1; + } + pgf_new_frame(); + pgf_connection(1); + return main_loop(&cl); +} |