diff options
Diffstat (limited to 'src/net/server.c')
| -rw-r--r-- | src/net/server.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/src/net/server.c b/src/net/server.c new file mode 100644 index 0000000..10d5d11 --- /dev/null +++ b/src/net/server.c @@ -0,0 +1,202 @@ +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <assert.h> +#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; i<count; i++) + { + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + client_socks->sockets[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_recv_hello(const uint8_t* payload, const uint8_t payload_len) +{ + assert(payload != NULL && payload_len < MAX_PLAYER_NAME_LENGTH && payload_len > 0); + + data_store* ds = datamodel(); + + for(int i=0; i<ds->players.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, payload, payload_len); + ds->players.players[i].player_name[payload_len] = '\0'; + } + + return true; +} + +card* server_recv_selected_card(const uint8_t* payload, const uint8_t payload_len) +{ + assert(payload != NULL && payload_len == 1); + + card* c = malloc(sizeof(card)); + assert(c != NULL); + *c = payload[0]; + + return c; +} + +uint8_t* server_recv_selected_stack(const uint8_t* payload, const uint8_t payload_len) +{ + assert(payload != NULL && payload_len == 1); + + uint8_t* index = malloc(sizeof(uint8_t)); + assert(index != NULL); + *index = payload[0]; + + return index; +} + +uint8_t server_send_start_game(uint8_t* payload, const uint8_t payload_len) +{ + uint16_t pos = 0; + data_store* ds = datamodel(); + player_list* players = &ds->players; + + payload[pos++] = players->count; + + // copy player_ids, length and nicknames to buffer + for(int i=0; i<players->count; i++) + { + pnoc_t* pl = &players->players[i]; + payload[pos++] = pl->player_id; + uint8_t len = strlen(pl->player_name); + payload[pos++] = len; + memcpy(payload+pos, pl->player_name, len); + payload += len; + } + + assert(pos <= payload_len); + + return pos; +} + +uint8_t server_send_selected_stack(uint8_t* payload, const uint8_t payload_len) +{ + data_store* ds = datamodel(); + + payload[0] = ds->stack_index; + + return 1; +} + +uint8_t server_send_deal_cards(uint8_t* payload, const uint8_t payload_len, const void* param) +{ + const hand_t* hand = (hand_t*) param; + + for(int i=0; i<MAX_HAND_CARDS; i++) + payload[i] = hand->cards[i]; + + return MAX_HAND_CARDS; +} + + +uint8_t server_send_initial_stacks(uint8_t* payload, const uint8_t payload_len) +{ + data_store* ds = datamodel(); + + for(int i=0; i<NUM_TABLE_STACKS; i++) + payload[i] = ds->table_stacks.stacks[i].cards[0]; + + return NUM_TABLE_STACKS; +} + |
