Sun, 23 Feb 2014 21:03:35 +0100
fixed network code + added game info and transmission of game info
src/main.c | file | annotate | diff | comparison | revisions | |
src/network.c | file | annotate | diff | comparison | revisions | |
src/network.h | file | annotate | diff | comparison | revisions | |
src/terminal-chess.h | file | annotate | diff | comparison | revisions |
--- a/src/main.c Wed Feb 05 14:07:43 2014 +0100 +++ b/src/main.c Sun Feb 23 21:03:35 2014 +0100 @@ -29,26 +29,58 @@ #include "terminal-chess.h" #include <string.h> +#include <time.h> int get_settings(int argc, char **argv, Settings *settings) { char *valid; + unsigned long int time, port; + uint8_t timeunit = 60; + size_t len; - for (char opt ; (opt = getopt(argc, argv, "hp:")) != -1 ;) { + for (char opt ; (opt = getopt(argc, argv, "a:bhp:rt:")) != -1 ;) { switch (opt) { - case 'p': - if (strtol(optarg, &valid, 10) < 1025 || *valid != '\0') { - fprintf(stderr, - "Invalid port number (%s) - choose a number > 1024\n", - optarg); - return 1; + case 'b': + settings->gameinfo.servercolor = BLACK; + break; + case 'r': + settings->gameinfo.servercolor = (rand()>>5) & 1 ? WHITE : BLACK; + break; + case 't': + case 'a': + len = strlen(optarg); + if (optarg[len-1] == 's') { + optarg[len-1] = '\0'; + timeunit = 1; + } + + if ((time = strtoul(optarg, &valid, 10)) > TIME_MAX + || *valid != '\0') { + fprintf(stderr, "Specified time is invalid (%s)\n", optarg); + return 1; + } else { + if (opt=='t') { + settings->gameinfo.time = timeunit * time; } else { - settings->port = optarg; + settings->gameinfo.addtime = time; } - break; - case 'h': - case '?': - settings->printhelp = 1; - break; + } + break; + case 'p': + port = strtol(optarg, &valid, 10); + if (port < 1025 || port > 65535 || *valid != '\0') { + fprintf(stderr, + "Invalid port number (%s) - choose a number between " + "1025 and 65535\n", + optarg); + return 1; + } else { + settings->port = optarg; + } + break; + case 'h': + case '?': + settings->printhelp = 1; + break; } } @@ -65,10 +97,31 @@ Settings default_settings() { Settings settings; memset(&settings, 0, sizeof(Settings)); + settings.gameinfo.servercolor = WHITE; settings.port = "27015"; return settings; } +void dump_gameinfo(Gameinfo *gameinfo) { + int serverwhite = gameinfo->servercolor == WHITE; + printf( + "Game details:\n" + " Server plays %s - Client plays %s\n", + serverwhite?"white":"black", serverwhite?"black":"White" + ); + if (gameinfo->time > 0) { + if (gameinfo->time % 60) { + printf(" Time limit: %ds + %ds\n", + gameinfo->time, gameinfo->addtime); + } else { + printf(" Time limit: %dm + %ds\n", + gameinfo->time/60, gameinfo->addtime); + } + } else { + printf(" No time limit\n"); + } +} + int cleanup(Settings *settings, int exitcode) { if (settings->server) { if (net_destroy(settings->server)) { @@ -80,17 +133,32 @@ } int main(int argc, char **argv) { + srand(time(NULL)); Settings settings = default_settings(); - get_settings(argc, argv, &settings); + if (get_settings(argc, argv, &settings)) { + return 1; + } if (settings.printhelp) { printf( - "Usage: %s [OPTION]... [HOST]\n" - "Starts/joins a network chess game\n\n" + "Usage: terminal-chess [OPTION]... [HOST]\n" + "Starts/joins a network chess game\n" + "\nGeneral options\n" " -h This help page\n" - " -p TCP port to use (default: 27015)\n", - argv[0]); + " -p TCP port to use (default: 27015)\n" + "\nServer options\n" + " -a <time> Specifies the time to add after each move\n" + " -b Server plays black pieces (default: white)\n" + " -r Distribute color randomly\n" + " -t <time> Specifies time limit (default: no limit)\n" + "\nNotes\n" + "White pieces are displayed as uppercase and black pieces as " + "lowercase letters.\n" + "The time unit for -a is seconds and for -t minutes by default. To " + "specify\nseconds for the -t option, use the s suffix.\n" + "Example: -t 150s\n" + ); return EXIT_SUCCESS; } @@ -98,6 +166,22 @@ settings.server = &server; if (is_server(&settings)) { + dump_gameinfo(&(settings.gameinfo)); + printf("\nListening for client...\n"); + if (net_create(&server, settings.port)) { + perror("Server creation failed"); + return cleanup(&settings, EXIT_FAILURE); + } + + if (net_listen(&server)) { + perror("Listening for client failed"); + return cleanup(&settings, EXIT_FAILURE); + } + + printf("Client connected - transmitting gameinfo...\n"); + net_send(server.client->fd, NETCODE_GAMEINFO, + &(settings.gameinfo), sizeof(settings.gameinfo)); + } else { if (net_find(&server, settings.serverhost, settings.port)) { perror("Can't find server"); return cleanup(&settings, EXIT_FAILURE); @@ -107,15 +191,14 @@ perror("Can't connect to server"); return cleanup(&settings, EXIT_FAILURE); } - } else { - if (net_create(&server, settings.port)) { - perror("Server creation failed"); - return cleanup(&settings, EXIT_FAILURE); - } - - if (net_listen(&server)) { - perror("Listening for client failed"); - return cleanup(&settings, EXIT_FAILURE); + + printf("Connection established!\n\n"); + if (net_recieve_code(server.fd) == NETCODE_GAMEINFO) { + net_recieve_data(server.fd, &(settings.gameinfo), + sizeof(settings.gameinfo)); + dump_gameinfo(&(settings.gameinfo)); + } else { + fprintf(stderr, "Server sent invalid gameinfo.\n"); } }
--- a/src/network.c Wed Feb 05 14:07:43 2014 +0100 +++ b/src/network.c Sun Feb 23 21:03:35 2014 +0100 @@ -31,14 +31,21 @@ #include <string.h> #include "network.h" -int server_bind(Server *server) { - server->fd = socket(server->info->ai_family, - server->info->ai_socktype, server->info->ai_protocol); +#define new_socket() socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + +int net_create(Server *server, char* port) { + server->info = NULL; + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(atoi(port)); + + server->fd = new_socket(); if (server->fd > -1) { int true = 1; setsockopt(server->fd, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(int)); - if (bind(server->fd, - server->info->ai_addr, server->info->ai_addrlen)) { + if (bind(server->fd, (struct sockaddr*)&addr, sizeof(addr))) { server->fd = -1; return 1; } else { @@ -49,10 +56,6 @@ } } -int net_create(Server *server, char* port) { - return net_find(server, "localhost", port) || server_bind(server); -} - int getaddrinfo_intrnl(char *host, char *port, struct addrinfo **info) { struct addrinfo hints; memset(&hints, 0, sizeof(hints)); @@ -82,21 +85,17 @@ } int net_connect(Server *server) { - struct addrinfo *info; - if (getaddrinfo_intrnl("localhost", NULL, &info)) { + + Client* client = calloc(1, sizeof(Client)); + client->fd = -1; + server->fd = new_socket(); + server->client = client; + + if (server->fd == -1) { return 1; } - Client* client = calloc(1, sizeof(Client)); - client->fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol); - server->client = client; - - freeaddrinfo(info); - if (client->fd == -1) { - return 1; - } - - return connect(client->fd, server->info->ai_addr, server->info->ai_addrlen); + return connect(server->fd, server->info->ai_addr, server->info->ai_addrlen); } int net_destroy(Server *server) { @@ -113,3 +112,19 @@ return EXIT_SUCCESS; } + +void net_send(int socket, uint32_t code, void *data, size_t len) { + code = htonl(code); + send(socket, &code, sizeof(uint32_t), 0); + send(socket, data, len, 0); +} + +int net_recieve_code(int socket) { + uint32_t code; + recv(socket, &code, sizeof(uint32_t), 0); + return ntohl(code); +} + +void net_recieve_data(int socket, void *data, size_t len) { + recv(socket, data, len, 0); +}
--- a/src/network.h Wed Feb 05 14:07:43 2014 +0100 +++ b/src/network.h Sun Feb 23 21:03:35 2014 +0100 @@ -36,16 +36,18 @@ #ifdef __cplusplus extern "C" { #endif + +#define NETCODE_GAMEINFO 1 typedef struct { - int fd; + int fd; /* -1, if we are the client */ struct sockaddr address; socklen_t address_len; } Client; typedef struct { int fd; - struct addrinfo* info; + struct addrinfo* info; /* NULL, if we are the server */ Client *client; } Server; @@ -56,6 +58,10 @@ int net_destroy(Server *server); int net_connect(Server *server); +void net_send(int socket, uint32_t code, void *data, size_t len); +int net_recieve_code(int socket); +void net_recieve_data(int socket, void *data, size_t len); + #ifdef __cplusplus }
--- a/src/terminal-chess.h Wed Feb 05 14:07:43 2014 +0100 +++ b/src/terminal-chess.h Sun Feb 23 21:03:35 2014 +0100 @@ -38,15 +38,26 @@ #ifdef __cplusplus extern "C" { #endif + +#define WHITE 0 +#define BLACK 1 +#define TIME_MAX UINT16_MAX + +typedef struct { + uint8_t servercolor; + uint16_t time; + uint16_t addtime; +} Gameinfo; typedef struct { - int printhelp; + uint8_t printhelp; + Gameinfo gameinfo; char* port; char* serverhost; /* NULL, if we are about to start a server */ Server *server; } Settings; -#define is_server(settings) ((settings)->serverhost) +#define is_server(settings) !((settings)->serverhost) #ifdef __cplusplus }