fixed network code + added game info and transmission of game info

Sun, 23 Feb 2014 21:03:35 +0100

author
Mike Becker <universe@uap-core.de>
date
Sun, 23 Feb 2014 21:03:35 +0100
changeset 2
0a08f79c320d
parent 1
e5fbb8f9edbe
child 3
3693fd2eb0e9

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
 }

mercurial