back to scratko.xyz
aboutsummaryrefslogtreecommitdiff
path: root/linux_client/client.c
diff options
context:
space:
mode:
authorscratko <m@scratko.xyz>2024-08-30 12:46:56 +0300
committerscratko <m@scratko.xyz>2024-08-30 14:59:44 +0300
commit831f9f01fbe4088eb6bd378c0e417d9996b676fd (patch)
tree53297459d35ad795618c351a79b1829776e5e1f4 /linux_client/client.c
parent4b6c15f780d59895f067383a5041edcfe86f504e (diff)
downloaddurak-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.c321
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);
+}