diff options
Diffstat (limited to 'src/net_server.c')
| -rw-r--r-- | src/net_server.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/src/net_server.c b/src/net_server.c new file mode 100644 index 0000000..39b6c51 --- /dev/null +++ b/src/net_server.c @@ -0,0 +1,203 @@ +#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 "net.h" +#include "player.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) +{ + 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[in] count Number of clients that should connect + * @return List of $count open sockets with connections to clients + */ +int* server_get_players(int serversock, const uint8_t count) +{ + int* clientsocks; + int i; + + assert(count < MAX_PLAYERS && count > 0); + + clientsocks = malloc(count*sizeof(int)); + if(clientsocks == NULL) + { + printf("server_get_players: Out of memory\n"); + exit(EXIT_FAILURE); + } + + // accept connections + for(i=0; i<count; i++) + { + int sock; + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + sock = accept(serversock, (struct sockaddr*) &addr, &addrlen); + if(sock == -1) + { + printf("accept: %s\n", strerror(sock)); + 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); + clientsocks[i] = sock; + } + + return clientsocks; +} + +void server_start_game(int* clients, const uint8_t clientcount, const struct player_list* players) +{ + uint8_t* buf; + uint8_t usercount = players->count; + uint32_t pos = 0; + uint32_t buflen = 2 + usercount; // type + usercount + (usercount * len) + + for(int i=0; i<usercount; i++) + buflen += strlen(players->names[i]); + + buf = malloc(buflen); + if(buf == NULL) + { + printf("server_start_game: Out of memory\n"); + exit(EXIT_FAILURE); + } + buf[pos++] = msg_type_start_game; + buf[pos++] = players->count; + // copy usernames with length to buffer + for(int i=0; i<usercount; i++) + { + uint8_t len = strlen(players->names[i]); + buf[pos++] = len; + memcpy(buf+pos, players->names[i], len); + pos += len; + } + + // send to all users + for(int i=0; i<clientcount; i++) + send(clients[i], buf, buflen, 0); + + free(buf); +} + +/** + * Server side function; receive hello message from client and read username + * @param[in] sock Socket to use + * @return Username of client + */ +static char* server_recv_hello(int sock) +{ + char buf[12], *name; + uint8_t namelen; + + recv(sock, buf, 12, 0); + + assert(buf[0] == msg_type_hello); + + namelen = buf[1]; + name = malloc(namelen+1); + if(name == NULL) + { + printf("sender_recv_hello: Out of memory\n"); + exit(EXIT_FAILURE); + } + + memcpy(name, buf+2, namelen); + name[namelen] = '\0'; + + return name; +} + +/** + * Server side function; calls correct handler for incoming packet + * @param[in] sock Socket to use + * @param[in] wanted Packet type that should be handled + * @return Pointer to desired data or NULL if not in recv queue + */ +void* server_recv(int sock, uint8_t wanted) +{ + void* result = NULL; + uint8_t buf[10], type; + ssize_t len = recv(sock, buf, 10, MSG_PEEK); // just peek into packet to determine type + + assert(len != -1); + + type = buf[0]; + if(type != wanted) + return NULL; + + switch(type) + { + case msg_type_hello: + result = server_recv_hello(sock); + break; + } + + return result; +} + |
