#include #include #include #include #include #include #include #include #include "server.h" #include "../global.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* ds = datamodel(); for(int i=0; iplayers.count; i++) { if(strlen(ds->players.players[i].player_name) > 0) // search for first empty (not yet assigned) slot continue; memcpy(ds->players.players[i].player_name, m->payload, m->hdr.payload_length); ds->players.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* ds = datamodel(); ds->selected_card = m->payload[0]; return true; } uint8_t* server_parse_selected_stack(const msg_t *m) { assert(m != NULL); assert(m->hdr.payload_length == 1); uint8_t* index = malloc(sizeof(uint8_t)); assert(index != NULL); *index = m->payload[0]; return index; } void server_prep_start_game(msg_t *m) { uint16_t pos = 0; data_store* ds = datamodel(); player_list* players = &ds->players; m->hdr.type = msg_type_start_game; m->payload[pos++] = players->count; // copy player_ids, length and nicknames to message payload for(int i=0; icount; i++) { pnoc_t* pl = &players->players[i]; m->payload[pos++] = pl->player_id; uint8_t len = strlen(pl->player_name); m->payload[pos++] = len; memcpy(m->payload+pos, pl->player_name, len); pos += len; } m->hdr.payload_length = pos; } void server_prep_selected_stack(msg_t *m) { data_store* ds = datamodel(); 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* ds = datamodel(); 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* ds = datamodel(); m->hdr.type = msg_type_selected_card_all; for(int i=0; iplayers.players[i]; if(pnoc->player_id == 0) // invalid player continue; m->payload[pos++] = pnoc->player_id; m->payload[pos++] = pnoc->open_card; } m->hdr.payload_length = pos; }