/***************************************************************************** * ___ __ __ ___ _ __ * * / _ \\ \/ // _ \ '_ \ * * | (_) |> <| __/ | | | * * \___//_/\_\\___|_| |_| * * * * The card game * * * * Copyright (C) 2011, Reiner Herrmann * * Mario Kilies * * * * 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 . * * * *****************************************************************************/ #include #include #include #include #include #include #include #include #include "client.h" #include "../data_store.h" #include "../player.h" #include "../game.h" /** * Client side function; connects to specified host:port * @param[in] host Hostname of server * @param[in] port Port of server * @return Socket with open connection to server or -1 on error */ int client_connect_server(const char* host, const char* port) { assert(host != NULL); assert(port != NULL); int status; int sock; struct addrinfo hints, *result, *tmp; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // IPv4 or IPv6 hints.ai_socktype = SOCK_STREAM; // TCP socket status = getaddrinfo(host, port, &hints, &result); if(status != 0) { printf("getaddrinfo: %s\n", gai_strerror(status)); exit(EXIT_FAILURE); } // connect to first result in linked addrinfo list for(tmp = result; tmp != NULL; tmp = tmp->ai_next) { // create socket sock = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol); if(sock == -1) continue; // connect! if(connect(sock, tmp->ai_addr, tmp->ai_addrlen) != -1) break; // Success! close(sock); } freeaddrinfo(result); if(tmp == NULL) return -1; return sock; } /** * Parse received list of players and fill global player list * @param[in] m Received message * @return Indicates success */ bool client_parse_player_list(const msg_t *m) { assert(m != NULL); data_store_t *ds = data_store(); uint32_t pos = 0; ds->player_list.count = m->payload[pos++]; // read usernames from buffer for(int i=0; iplayer_list.count; i++) { uint8_t namelen; ds->player_list.players[i].player_id = m->payload[pos++]; namelen = m->payload[pos++]; assert(namelen <= MAX_PLAYER_NAME_LENGTH); strncpy(ds->player_list.players[i].player_name, (const char*) m->payload+pos, namelen); ds->player_list.players[i].player_name[namelen] = '\0'; pos += namelen; } return true; } /** * Parse received hand and store it * @param[in] m Received message * @return Indicates success */ bool client_parse_deal_hand(const msg_t *m) { assert(m != NULL); assert(m->hdr.payload_length == MAX_HAND_CARDS); // deal_cards packet have fixed size data_store_t *ds = data_store(); for(int i=0; ihand.cards[i] = m->payload[i]; return true; } /** * Parse received index of a selected stack and store it * @param[in] m Received message * @return Indicates success */ bool client_parse_selected_stack(const msg_t *m) { assert(m != NULL); assert(m->hdr.payload_length == 1); data_store_t *ds = data_store(); ds->stack_index = m->payload[0]; assert(ds->stack_index <= NUM_TABLE_STACKS); return true; } /** * Parse received cards for initial stacks at beginning of game * @param[in] m Received message * @return Indicates success */ bool client_parse_initial_stacks(const msg_t *m) { assert(m != NULL); assert(m->hdr.payload_length == NUM_TABLE_STACKS); data_store_t *ds = data_store(); for(int i=0; itable_stacks.stacks[i].cards[0] = m->payload[i]; return true; } /** * Parse received open cards of all players * @param[in] m Received message * @return Indicates success */ bool client_parse_selected_card_all(const msg_t *m) { assert(m != NULL); assert(m->hdr.payload_length % 2 == 0); // payload: n times id+card data_store_t *ds = data_store(); for(int i=0; ihdr.payload_length; i+=2) { player_id_t pid = m->payload[i]; player_list_entry_t *ple = get_player_list_entry_by_player_id(&ds->player_list, pid); ple->open_card = m->payload[i+1]; } return true; } /** * Parse received action for next round (whether new cards will be dealt ot the game is ending) * @param[in] m Received message * @return Indicates success */ bool client_parse_next_action(const msg_t *m) { assert(m != NULL); assert(m->hdr.payload_length == 1); data_store_t *ds = data_store(); ds->game_finished = m->payload[0]; return true; } /** * Parse received hello answer from server with assigned player id * @param[in] m Received message * @return Indicates success */ bool client_parse_hello(const msg_t *m) { assert(m != NULL); assert(m->hdr.payload_length == 1); data_store_t *ds = data_store(); ds->own_player_id = m->payload[0]; return true; } /** * Prepare hello message with client's nickname\n * Payload format:\n * [ nickname:strlen(nickname) ] * @param[out] m Pointer to message that should be filled */ void client_prep_hello(msg_t *m) { data_store_t *ds = data_store(); uint8_t namelen = strlen(ds->nickname); m->hdr.type = msg_type_hello_c; memcpy(m->payload, ds->nickname, namelen); m->hdr.payload_length = namelen; } /** * Prepare message with selected card\n * Payload format:\n * [ selected_card:1 ] * @param[out] m Pointer to message that should be filled */ void client_prep_selected_card(msg_t *m) { data_store_t *ds = data_store(); card c = ds->selected_card; assert(c >= MIN_CARD && c <= MAX_CARD); m->hdr.type = msg_type_selected_card; m->payload[0] = c; m->hdr.payload_length = 1; } /** * Prepare message with selected stack\n * Payload format:\n * [ stack_index:1 ] * @param[out] m Pointer to message that should be filled */ void client_prep_selected_stack(msg_t *m) { data_store_t *ds = data_store(); assert(ds->stack_index <= NUM_TABLE_STACKS); m->hdr.type = msg_type_selected_stack_c; m->payload[0] = ds->stack_index; m->hdr.payload_length = 1; }