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
     1.1 --- a/src/main.c	Wed Feb 05 14:07:43 2014 +0100
     1.2 +++ b/src/main.c	Sun Feb 23 21:03:35 2014 +0100
     1.3 @@ -29,26 +29,58 @@
     1.4  
     1.5  #include "terminal-chess.h"
     1.6  #include <string.h>
     1.7 +#include <time.h>
     1.8  
     1.9  int get_settings(int argc, char **argv, Settings *settings) {
    1.10      char *valid;
    1.11 +    unsigned long int time, port;
    1.12 +    uint8_t timeunit = 60;
    1.13 +    size_t len;
    1.14      
    1.15 -    for (char opt ; (opt = getopt(argc, argv, "hp:")) != -1 ;) {
    1.16 +    for (char opt ; (opt = getopt(argc, argv, "a:bhp:rt:")) != -1 ;) {
    1.17          switch (opt) {
    1.18 -            case 'p':
    1.19 -                if (strtol(optarg, &valid, 10) < 1025 || *valid != '\0') {
    1.20 -                    fprintf(stderr,
    1.21 -                        "Invalid port number (%s) - choose a number > 1024\n",
    1.22 -                        optarg);
    1.23 -                    return 1;
    1.24 +        case 'b':
    1.25 +            settings->gameinfo.servercolor = BLACK;
    1.26 +            break;
    1.27 +        case 'r':
    1.28 +            settings->gameinfo.servercolor = (rand()>>5) & 1 ? WHITE : BLACK;
    1.29 +            break;
    1.30 +        case 't':
    1.31 +        case 'a':
    1.32 +            len = strlen(optarg);
    1.33 +            if (optarg[len-1] == 's') {
    1.34 +                optarg[len-1] = '\0';
    1.35 +                timeunit = 1;
    1.36 +            }
    1.37 +            
    1.38 +            if ((time = strtoul(optarg, &valid, 10)) > TIME_MAX
    1.39 +                || *valid != '\0') {
    1.40 +                fprintf(stderr, "Specified time is invalid (%s)\n", optarg);
    1.41 +                return 1;
    1.42 +            } else {
    1.43 +                if (opt=='t') {
    1.44 +                    settings->gameinfo.time = timeunit * time;
    1.45                  } else {
    1.46 -                    settings->port = optarg;
    1.47 +                    settings->gameinfo.addtime = time;
    1.48                  }
    1.49 -                break;
    1.50 -            case 'h':
    1.51 -            case '?':
    1.52 -                settings->printhelp = 1;
    1.53 -                break;
    1.54 +            }
    1.55 +            break;
    1.56 +        case 'p':
    1.57 +            port = strtol(optarg, &valid, 10);
    1.58 +            if (port < 1025 || port > 65535 || *valid != '\0') {
    1.59 +                fprintf(stderr,
    1.60 +                    "Invalid port number (%s) - choose a number between "
    1.61 +                    "1025 and 65535\n",
    1.62 +                    optarg);
    1.63 +                return 1;
    1.64 +            } else {
    1.65 +                settings->port = optarg;
    1.66 +            }
    1.67 +            break;
    1.68 +        case 'h':
    1.69 +        case '?':
    1.70 +            settings->printhelp = 1;
    1.71 +            break;
    1.72          }
    1.73      }
    1.74      
    1.75 @@ -65,10 +97,31 @@
    1.76  Settings default_settings() {
    1.77      Settings settings;
    1.78      memset(&settings, 0, sizeof(Settings));
    1.79 +    settings.gameinfo.servercolor = WHITE;
    1.80      settings.port = "27015";
    1.81      return settings;
    1.82  }
    1.83  
    1.84 +void dump_gameinfo(Gameinfo *gameinfo) {
    1.85 +    int serverwhite = gameinfo->servercolor == WHITE;
    1.86 +    printf(
    1.87 +        "Game details:\n"
    1.88 +        "  Server plays %s  -  Client plays %s\n",
    1.89 +        serverwhite?"white":"black", serverwhite?"black":"White"
    1.90 +    );
    1.91 +    if (gameinfo->time > 0) {
    1.92 +        if (gameinfo->time % 60) {
    1.93 +            printf("  Time limit: %ds + %ds\n",
    1.94 +                gameinfo->time, gameinfo->addtime);
    1.95 +        } else {
    1.96 +            printf("  Time limit: %dm + %ds\n",
    1.97 +                gameinfo->time/60, gameinfo->addtime);
    1.98 +        }
    1.99 +    } else {
   1.100 +        printf("  No time limit\n");
   1.101 +    }
   1.102 +}
   1.103 +
   1.104  int cleanup(Settings *settings, int exitcode) {
   1.105      if (settings->server) {
   1.106          if (net_destroy(settings->server)) {
   1.107 @@ -80,17 +133,32 @@
   1.108  }
   1.109  
   1.110  int main(int argc, char **argv) {
   1.111 +    srand(time(NULL));
   1.112      
   1.113      Settings settings = default_settings();
   1.114 -    get_settings(argc, argv, &settings);
   1.115 +    if (get_settings(argc, argv, &settings)) {
   1.116 +        return 1;
   1.117 +    }
   1.118      
   1.119      if (settings.printhelp) {
   1.120          printf(
   1.121 -            "Usage: %s [OPTION]... [HOST]\n"
   1.122 -            "Starts/joins a network chess game\n\n"
   1.123 +            "Usage: terminal-chess [OPTION]... [HOST]\n"
   1.124 +            "Starts/joins a network chess game\n"
   1.125 +            "\nGeneral options\n"
   1.126              "  -h            This help page\n"
   1.127 -            "  -p            TCP port to use (default: 27015)\n",
   1.128 -            argv[0]);
   1.129 +            "  -p            TCP port to use (default: 27015)\n"
   1.130 +            "\nServer options\n"
   1.131 +            "  -a <time>     Specifies the time to add after each move\n"
   1.132 +            "  -b            Server plays black pieces (default: white)\n"
   1.133 +            "  -r            Distribute color randomly\n"
   1.134 +            "  -t <time>     Specifies time limit (default: no limit)\n"
   1.135 +            "\nNotes\n"
   1.136 +            "White pieces are displayed as uppercase and black pieces as "
   1.137 +            "lowercase letters.\n"
   1.138 +            "The time unit for -a is seconds and for -t minutes by default. To "
   1.139 +            "specify\nseconds for the -t option, use the s suffix.\n"
   1.140 +            "Example: -t 150s\n"
   1.141 +        );
   1.142          return EXIT_SUCCESS;
   1.143      }
   1.144      
   1.145 @@ -98,6 +166,22 @@
   1.146      settings.server = &server;
   1.147      
   1.148      if (is_server(&settings)) {
   1.149 +        dump_gameinfo(&(settings.gameinfo));
   1.150 +        printf("\nListening for client...\n");
   1.151 +        if (net_create(&server, settings.port)) {
   1.152 +            perror("Server creation failed");
   1.153 +            return cleanup(&settings, EXIT_FAILURE);
   1.154 +        }
   1.155 +        
   1.156 +        if (net_listen(&server)) {
   1.157 +            perror("Listening for client failed");
   1.158 +            return cleanup(&settings, EXIT_FAILURE);
   1.159 +        }
   1.160 +        
   1.161 +        printf("Client connected - transmitting gameinfo...\n");
   1.162 +        net_send(server.client->fd, NETCODE_GAMEINFO,
   1.163 +            &(settings.gameinfo), sizeof(settings.gameinfo));
   1.164 +    } else {
   1.165          if (net_find(&server, settings.serverhost, settings.port)) {
   1.166              perror("Can't find server");
   1.167              return cleanup(&settings, EXIT_FAILURE);
   1.168 @@ -107,15 +191,14 @@
   1.169              perror("Can't connect to server");
   1.170              return cleanup(&settings, EXIT_FAILURE);
   1.171          }
   1.172 -    } else {
   1.173 -        if (net_create(&server, settings.port)) {
   1.174 -            perror("Server creation failed");
   1.175 -            return cleanup(&settings, EXIT_FAILURE);
   1.176 -        }
   1.177 -        
   1.178 -        if (net_listen(&server)) {
   1.179 -            perror("Listening for client failed");
   1.180 -            return cleanup(&settings, EXIT_FAILURE);
   1.181 +
   1.182 +        printf("Connection established!\n\n");
   1.183 +        if (net_recieve_code(server.fd) == NETCODE_GAMEINFO) {
   1.184 +            net_recieve_data(server.fd, &(settings.gameinfo),
   1.185 +                sizeof(settings.gameinfo));
   1.186 +            dump_gameinfo(&(settings.gameinfo));
   1.187 +        } else {
   1.188 +            fprintf(stderr, "Server sent invalid gameinfo.\n");
   1.189          }
   1.190      }
   1.191      
     2.1 --- a/src/network.c	Wed Feb 05 14:07:43 2014 +0100
     2.2 +++ b/src/network.c	Sun Feb 23 21:03:35 2014 +0100
     2.3 @@ -31,14 +31,21 @@
     2.4  #include <string.h>
     2.5  #include "network.h"
     2.6  
     2.7 -int server_bind(Server *server) {
     2.8 -    server->fd = socket(server->info->ai_family,
     2.9 -        server->info->ai_socktype, server->info->ai_protocol);
    2.10 +#define new_socket() socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    2.11 +
    2.12 +int net_create(Server *server, char* port) {
    2.13 +    server->info = NULL;
    2.14 +    
    2.15 +    struct sockaddr_in addr;
    2.16 +    addr.sin_family = AF_INET;
    2.17 +    addr.sin_addr.s_addr = INADDR_ANY;
    2.18 +    addr.sin_port = htons(atoi(port));
    2.19 +    
    2.20 +    server->fd = new_socket();
    2.21      if (server->fd > -1) {
    2.22          int true = 1;
    2.23          setsockopt(server->fd, SOL_SOCKET, SO_REUSEADDR, &true, sizeof(int));
    2.24 -        if (bind(server->fd,
    2.25 -                server->info->ai_addr, server->info->ai_addrlen)) {
    2.26 +        if (bind(server->fd, (struct sockaddr*)&addr, sizeof(addr))) {
    2.27              server->fd = -1;
    2.28              return 1;
    2.29          } else {
    2.30 @@ -49,10 +56,6 @@
    2.31      }
    2.32  }
    2.33  
    2.34 -int net_create(Server *server, char* port) {
    2.35 -    return net_find(server, "localhost", port) || server_bind(server);
    2.36 -}
    2.37 -
    2.38  int getaddrinfo_intrnl(char *host, char *port, struct addrinfo **info) {
    2.39      struct addrinfo hints;
    2.40      memset(&hints, 0, sizeof(hints));
    2.41 @@ -82,21 +85,17 @@
    2.42  }
    2.43  
    2.44  int net_connect(Server *server) {
    2.45 -    struct addrinfo *info;
    2.46 -    if (getaddrinfo_intrnl("localhost", NULL, &info)) {
    2.47 +    
    2.48 +    Client* client = calloc(1, sizeof(Client));
    2.49 +    client->fd = -1;
    2.50 +    server->fd = new_socket();
    2.51 +    server->client = client;
    2.52 +    
    2.53 +    if (server->fd == -1) {
    2.54          return 1;
    2.55      }
    2.56      
    2.57 -    Client* client = calloc(1, sizeof(Client));
    2.58 -    client->fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
    2.59 -    server->client = client;
    2.60 -    
    2.61 -    freeaddrinfo(info);
    2.62 -    if (client->fd == -1) {
    2.63 -        return 1;
    2.64 -    }
    2.65 -    
    2.66 -    return connect(client->fd, server->info->ai_addr, server->info->ai_addrlen);
    2.67 +    return connect(server->fd, server->info->ai_addr, server->info->ai_addrlen);
    2.68  }
    2.69  
    2.70  int net_destroy(Server *server) {
    2.71 @@ -113,3 +112,19 @@
    2.72      
    2.73      return EXIT_SUCCESS;
    2.74  }
    2.75 +
    2.76 +void net_send(int socket, uint32_t code, void *data, size_t len) {
    2.77 +    code = htonl(code);
    2.78 +    send(socket, &code, sizeof(uint32_t), 0);
    2.79 +    send(socket, data, len, 0);
    2.80 +}
    2.81 +
    2.82 +int net_recieve_code(int socket) {
    2.83 +    uint32_t code;
    2.84 +    recv(socket, &code, sizeof(uint32_t), 0);
    2.85 +    return ntohl(code);
    2.86 +}
    2.87 +
    2.88 +void net_recieve_data(int socket, void *data, size_t len) {
    2.89 +    recv(socket, data, len, 0);
    2.90 +}
     3.1 --- a/src/network.h	Wed Feb 05 14:07:43 2014 +0100
     3.2 +++ b/src/network.h	Sun Feb 23 21:03:35 2014 +0100
     3.3 @@ -36,16 +36,18 @@
     3.4  #ifdef	__cplusplus
     3.5  extern "C" {
     3.6  #endif
     3.7 +    
     3.8 +#define NETCODE_GAMEINFO 1
     3.9  
    3.10  typedef struct {
    3.11 -    int fd;
    3.12 +    int fd; /* -1, if we are the client */
    3.13      struct sockaddr address;
    3.14      socklen_t address_len;
    3.15  } Client;
    3.16  
    3.17  typedef struct {
    3.18      int fd;
    3.19 -    struct addrinfo* info;
    3.20 +    struct addrinfo* info; /* NULL, if we are the server */
    3.21      Client *client;
    3.22  } Server;
    3.23  
    3.24 @@ -56,6 +58,10 @@
    3.25  int net_destroy(Server *server);
    3.26  int net_connect(Server *server);
    3.27  
    3.28 +void net_send(int socket, uint32_t code, void *data, size_t len);
    3.29 +int net_recieve_code(int socket);
    3.30 +void net_recieve_data(int socket, void *data, size_t len);
    3.31 +
    3.32  
    3.33  #ifdef	__cplusplus
    3.34  }
     4.1 --- a/src/terminal-chess.h	Wed Feb 05 14:07:43 2014 +0100
     4.2 +++ b/src/terminal-chess.h	Sun Feb 23 21:03:35 2014 +0100
     4.3 @@ -38,15 +38,26 @@
     4.4  #ifdef	__cplusplus
     4.5  extern "C" {
     4.6  #endif
     4.7 +    
     4.8 +#define WHITE 0
     4.9 +#define BLACK 1
    4.10 +#define TIME_MAX UINT16_MAX
    4.11 +    
    4.12 +typedef struct {
    4.13 +    uint8_t servercolor;
    4.14 +    uint16_t time;
    4.15 +    uint16_t addtime;
    4.16 +} Gameinfo;
    4.17  
    4.18  typedef struct {
    4.19 -    int printhelp;
    4.20 +    uint8_t printhelp;
    4.21 +    Gameinfo gameinfo;
    4.22      char* port;
    4.23      char* serverhost; /* NULL, if we are about to start a server */
    4.24      Server *server;
    4.25  } Settings;
    4.26  
    4.27 -#define is_server(settings) ((settings)->serverhost)
    4.28 +#define is_server(settings) !((settings)->serverhost)
    4.29  
    4.30  #ifdef	__cplusplus
    4.31  }

mercurial