#include #include #include /* _getch() */ #include #include #include #include /* 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) && !cl->read_data) { if(!cl->data_left_in_buffer) { cl->data_left_in_buffer = recv(cl->fd, cl->buffer, max_buffer_size, 0); /* end of file -- closed connection (from server) */ if(!cl->data_left_in_buffer) { clean_up_resources(cl); WSACleanup(); 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 int fill_in_buffer(struct client *cl, int *data_size, INPUT_RECORD *irInBuf) { int i, buffer_idx, end_status = 0, input_status = 0; int key; for(i = 0, buffer_idx = 0; i < *data_size; ++i) { if(irInBuf[i].Event.KeyEvent.bKeyDown) { key = irInBuf[i].Event.KeyEvent.uChar.AsciiChar; if(key != '\n' && key != '\r' && (key < 'A' || key > 'z' )) { return 0; } cl->buffer[buffer_idx] = key; putchar(key); if(key == '\n' || key == '\r') { cl->buffer[buffer_idx] = '\n'; end_status = 1; } ++buffer_idx; input_status = 1; } } /* no data was input */ if(!input_status) return 0; /* the data has not yet been entered up to the newline character */ if(!end_status && input_status) { for(; (key = _getch()) != '\r'; ) { if(key == backspace && buffer_idx > 0) { --buffer_idx; cl->buffer[buffer_idx] = '\0'; putchar(backspace); putchar(' '); putchar(backspace); continue; } else if(key == backspace) continue; cl->buffer[buffer_idx] = key; ++buffer_idx; putchar(key); } cl->buffer[buffer_idx] = '\n'; putchar('\n'); ++buffer_idx; /* like size of buffer */ } *data_size = buffer_idx; return 1; } static void send_data_to_server(struct client *cl) { DWORD cNumRead; int input_result = 0, data_size; INPUT_RECORD irInBuf[128]; if(cl->read_data) { ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), irInBuf, 128, &cNumRead); data_size = (int) cNumRead; /* data_size will be changed */ if(!fill_in_buffer(cl, &data_size, irInBuf)) { cl->read_data = 0; return; } if(check_users_exit(cl->state, cl->buffer, data_size)) { closesocket(cl->fd); clean_up_resources(cl); pgf_disconnect(); WSACleanup(); 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; cl->read_data = 0; } } 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; } static int key_was_pressed() { return WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0) == WAIT_OBJECT_0; } static void wait_for_key_press() { WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), INFINITE); } int main_loop(struct client *cl) { struct timeval timeout; int select_result, error; fd_set readfds; DWORD fdwMode; fdwMode = ENABLE_WINDOW_INPUT | ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), fdwMode); for(;;) { FD_ZERO(&readfds); FD_SET(cl->fd, &readfds); if(check_tracking_client_input(cl->state, cl->pending_server_response)) { if(cl->state == attack || cl->state == defense || cl->state == tossing) { wait_for_key_press(); if(key_was_pressed()) cl->read_data = 1; } else if(key_was_pressed()) { cl->read_data = 1; } } if(!cl->data_left_in_buffer && !cl->read_data) { if(cl->state == first_player || cl->state == confirmation_waiting) { timeout.tv_sec = 1; timeout.tv_usec = 0; } select_result = select(cl->fd + 1, &readfds, NULL, NULL, cl->state == first_player || cl->state == confirmation_waiting ? &timeout : NULL); if(select_result == SOCKET_ERROR) { error = WSAGetLastError(); if(error == WSANOTINITIALISED) printf("WSANOTINITIALISED\n"); else if(error == WSAEFAULT) printf("WSAEFAULT\n"); else if(error == WSAENETDOWN) printf("WSAENETDOWN\n"); else if(error == WSAEINVAL) printf("WSAEINVAL\n"); else if(error == WSAEINTR) printf("WSAEINTR\n"); else if(error == WSAEINPROGRESS) printf("WSAEINPROGRESS\n"); else if(error == WSAENOTSOCK) printf("WSAENOTSOCK\n"); 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); } } 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; cl->read_data = 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; static WSADATA wsaData; int wsaerr = WSAStartup(MAKEWORD(2, 0), &wsaData); if (wsaerr) exit(1); 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); }