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 |
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 }