#include #include #include #include #include #include #include #include #include "server.h" #include "../data_store.h" /** * Server side function; start server on specified port * @param[in] port Port on which server should listen * @return Listening socket */ int server_start(const char* port) { assert(port != NULL); int status; int serversock; struct addrinfo hints, *result, *tmp; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; // IPv4 or IPv6 hints.ai_socktype = SOCK_STREAM; // TCP socket hints.ai_flags = AI_PASSIVE; // wildcard IP hints.ai_protocol = 0; // any protocol status = getaddrinfo(NULL, port, &hints, &result); if(status != 0) { printf("getaddrinfo: %s\n", gai_strerror(status)); exit(EXIT_FAILURE); } // iterate over linked addrinfo list and use first useable entry for(tmp = result; tmp != NULL; tmp = tmp->ai_next) { int yes=1; // create socket serversock = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol); if(serversock == -1) continue; // try to reuse still open sockets in TIME_WAIT state setsockopt(serversock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); // try to bind to address/port if(bind(serversock, tmp->ai_addr, tmp->ai_addrlen) == 0) break; // Success! close(serversock); } if(tmp == NULL) { printf("failed to bind\n"); exit(EXIT_FAILURE); } freeaddrinfo(result); // start listening status = listen(serversock, 1); if(status == -1) { printf("listen: %s\n", strerror(status)); exit(EXIT_FAILURE); } return serversock; } /** * Server side function; accepts connections from clients * @param[in] serversock Socket on which server is listening * @param[out] client_socks Socket list in which to store open client connections * @param[in] count Number of clients that should connect */ void server_get_players(int serversock, socket_list_t* client_socks, const uint8_t count) { int i; assert(count < MAX_PLAYERS && count > 0); // accept connections for(i=0; isockets[i] = accept(serversock, (struct sockaddr*) &addr, &addrlen); if(client_socks->sockets[i] == -1) { printf("accept: %s\n", strerror(client_socks->sockets[i])); exit(EXIT_FAILURE); } //printf("new client connected: %s\n", inet_ntop(sock.ss_family, get_in_addr((struct sockaddr*)&sock), INET6_ADDRSTRLEN)); printf("new client connected (%d/%d)\n", i+1, count); } client_socks->count = count; } /** * Server side function; receive hello message from client and read username * @param[in] sock Socket to use * @return Username of client */ bool server_parse_hello(const msg_t *m) { assert(m != NULL); assert(m->hdr.payload_length > 0); assert(m->hdr.payload_length < MAX_PLAYER_NAME_LENGTH); data_store_t *ds = data_store(); for(int i=0; iplayer_list.count; i++) { if(strlen(ds->player_list.players[i].player_name) > 0) // search for first empty (not yet assigned) slot continue; memcpy(ds->player_list.players[i].player_name, m->payload, m->hdr.payload_length); ds->player_list.players[i].player_name[m->hdr.payload_length] = '\0'; } return true; } bool server_parse_selected_card(const msg_t *m) { assert(m != NULL); assert(m->hdr.payload_length == 1); data_store_t *ds = data_store(); ds->selected_card = m->payload[0]; return true; } bool server_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; } void server_prep_start_game(msg_t *m) { uint16_t pos = 0; data_store_t *ds = data_store(); player_list_t *player_list = &ds->player_list; m->hdr.type = msg_type_start_game; m->payload[pos++] = player_list->count; // copy player_ids, length and nicknames to message payload for(int i = 0; i < player_list->count; i++) { player_list_entry_t *ple = &player_list->players[i]; m->payload[pos++] = ple->player_id; uint8_t len = strlen(ple->player_name); m->payload[pos++] = len; memcpy(m->payload+pos, ple->player_name, len); pos += len; } m->hdr.payload_length = pos; } void server_prep_hello(msg_t *m, const player_list_entry_t* player) { m->hdr.type = msg_type_hello_s; m->payload[0] = player->player_id; m->hdr.payload_length = 1; } void server_prep_selected_stack(msg_t *m) { data_store_t *ds = data_store(); m->hdr.type = msg_type_selected_stack_s; m->payload[0] = ds->stack_index; m->hdr.payload_length = 1; } void server_prep_deal_hand(msg_t *m, const hand_t *h) { assert(h != NULL); m->hdr.type = msg_type_deal_hand; for(int i=0; ipayload[i] = h->cards[i]; m->hdr.payload_length = MAX_HAND_CARDS; } void server_prep_initial_stacks(msg_t *m) { data_store_t *ds = data_store(); m->hdr.type = msg_type_initial_stacks; for(int i=0; ipayload[i] = ds->table_stacks.stacks[i].cards[0]; m->hdr.payload_length = NUM_TABLE_STACKS; } void server_prep_selected_card_all(msg_t *m) { uint8_t pos = 0; data_store_t *ds = data_store(); m->hdr.type = msg_type_selected_card_all; for(int i = 0; i < ds->player_list.count; i++) { player_list_entry_t *ple = &ds->player_list.players[i]; if(ple->player_id == 0) // invalid player continue; m->payload[pos++] = ple->player_id; m->payload[pos++] = ple->open_card; } m->hdr.payload_length = pos; }