added nonblocking read for network games + minor build system fixes

Wed, 09 Apr 2014 12:07:47 +0200

author
Mike Becker <universe@uap-core.de>
date
Wed, 09 Apr 2014 12:07:47 +0200
changeset 34
c4d4b8a8f902
parent 33
866025982aa9
child 35
6c64b7a073af

added nonblocking read for network games + minor build system fixes

src/Makefile file | annotate | diff | comparison | revisions
src/chess/Makefile file | annotate | diff | comparison | revisions
src/client.c file | annotate | diff | comparison | revisions
src/game.c file | annotate | diff | comparison | revisions
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/server.c file | annotate | diff | comparison | revisions
     1.1 --- a/src/Makefile	Wed Apr 09 11:12:04 2014 +0200
     1.2 +++ b/src/Makefile	Wed Apr 09 12:07:47 2014 +0200
     1.3 @@ -38,18 +38,18 @@
     1.4  OBJ = $(SRC:%.c=../build/release/%$(OBJ_EXT))
     1.5  OBJ_D = $(SRC:%.c=../build/debug/%$(OBJ_EXT))
     1.6  
     1.7 -all: $(OBJ)
     1.8 -	$(LD) -o ../build/release/$(BIN) $^ \
     1.9 +all: ../build/release $(OBJ)
    1.10 +	$(LD) -o ../build/release/$(BIN) $(OBJ) \
    1.11  	../build/release/chess$(LIB_EXT) $(LDFLAGS)
    1.12  
    1.13 -debug: $(OBJ_D)
    1.14 -	$(LD) -o ../build/debug/$(BIN) $^ \
    1.15 +debug: ../build/debug $(OBJ_D)
    1.16 +	$(LD) -o ../build/debug/$(BIN) $(OBJ_D) \
    1.17  	../build/debug/chess$(LIB_EXT) $(LDFLAGS)	
    1.18  
    1.19 -../build/release/%$(OBJ_EXT): %.c ../build/release
    1.20 +../build/release/%$(OBJ_EXT): %.c
    1.21  	$(CC) -o $@ $(CFLAGS) -c $<
    1.22  
    1.23 -../build/debug/%$(OBJ_EXT): %.c ../build/debug
    1.24 +../build/debug/%$(OBJ_EXT): %.c
    1.25  	$(CC) -o $@ $(CFLAGS_D) -c $<
    1.26  	
    1.27  ../build/release:
     2.1 --- a/src/chess/Makefile	Wed Apr 09 11:12:04 2014 +0200
     2.2 +++ b/src/chess/Makefile	Wed Apr 09 12:07:47 2014 +0200
     2.3 @@ -42,16 +42,16 @@
     2.4  OBJ = $(SRC:%.c=$(BUILDDIR)/release/%$(OBJ_EXT))
     2.5  OBJ_D = $(SRC:%.c=$(BUILDDIR)/debug/%$(OBJ_EXT))
     2.6  
     2.7 -all: $(OBJ)
     2.8 +all: $(BUILDDIR)/release $(OBJ)
     2.9  	$(AR) $(ARFLAGS) $(BUILDDIR)/release/chess$(LIB_EXT) $(OBJ)
    2.10  
    2.11 -debug: $(OBJ_D)
    2.12 +debug: $(BUILDDIR)/debug $(OBJ_D)
    2.13  	$(AR) $(ARFLAGS) $(BUILDDIR)/debug/chess$(LIB_EXT) $(OBJ_D)	
    2.14  
    2.15 -$(BUILDDIR)/release/%$(OBJ_EXT): %.c $(BUILDDIR)/release
    2.16 +$(BUILDDIR)/release/%$(OBJ_EXT): %.c
    2.17  	$(CC) -o $@ $(CFLAGS) -c $<
    2.18  	
    2.19 -$(BUILDDIR)/debug/%$(OBJ_EXT): %.c $(BUILDDIR)/debug
    2.20 +$(BUILDDIR)/debug/%$(OBJ_EXT): %.c
    2.21  	$(CC) -o $@ $(CFLAGS_D) -c $<
    2.22  
    2.23  $(BUILDDIR):
     3.1 --- a/src/client.c	Wed Apr 09 11:12:04 2014 +0200
     3.2 +++ b/src/client.c	Wed Apr 09 12:07:47 2014 +0200
     3.3 @@ -34,12 +34,12 @@
     3.4  
     3.5  static int client_connect(Server *server, char *host, char *port) {
     3.6      if (net_find(server, host, port)) {
     3.7 -        fprintf(stderr, "Can't find server\n");
     3.8 +        addstr("Can't find server");
     3.9          return 1;
    3.10      }
    3.11  
    3.12      if (net_connect(server)) {
    3.13 -        perror("Can't connect to server");
    3.14 +        addstr("Can't connect to server");
    3.15          return 1;
    3.16      }
    3.17      
    3.18 @@ -48,7 +48,7 @@
    3.19  
    3.20  static int client_handshake(Server *server) {
    3.21      if (net_recieve_code(server->fd) != NETCODE_VERSION) {
    3.22 -        fprintf(stderr, "Server uses an incompatible software version.\n");
    3.23 +        addstr("Server uses an incompatible software version.");
    3.24          return 1;
    3.25      } else {
    3.26          net_send_code(server->fd, NETCODE_VERSION);
    3.27 @@ -84,7 +84,7 @@
    3.28              net_send_code(server.fd, NETCODE_DECLINE);
    3.29          }
    3.30      } else {
    3.31 -        fprintf(stderr, "Server sent invalid gameinfo.\n");
    3.32 +        addstr("Server sent invalid gameinfo.");
    3.33          net_destroy(&server);
    3.34          return EXIT_FAILURE;
    3.35      }
     4.1 --- a/src/game.c	Wed Apr 09 11:12:04 2014 +0200
     4.2 +++ b/src/game.c	Wed Apr 09 12:07:47 2014 +0200
     4.3 @@ -33,6 +33,7 @@
     4.4  #include <ncurses.h>
     4.5  #include <string.h>
     4.6  #include <inttypes.h>
     4.7 +#include <sys/select.h>
     4.8  
     4.9  static const uint8_t boardx = 10, boardy = 10;
    4.10  static int inputy = 21; /* should be overridden on game startup */
    4.11 @@ -315,6 +316,13 @@
    4.12  
    4.13  static int recvmove(GameState *gamestate, GameInfo *gameinfo, int opponent) {
    4.14      
    4.15 +    if (net_setnonblocking(opponent, 1)) {
    4.16 +        printw("Cannot setup nonblocking IO on network socket");
    4.17 +        cbreak(); getch();
    4.18 +        exit(EXIT_FAILURE);
    4.19 +    }
    4.20 +    
    4.21 +    struct timeval timeout;
    4.22      while (1) {
    4.23          timecontrol(gamestate, gameinfo);
    4.24          
    4.25 @@ -323,52 +331,66 @@
    4.26          clrtoeol();
    4.27          refresh();
    4.28  
    4.29 -        // TODO: nonblocking
    4.30 -        uint32_t code = net_recieve_code(opponent);
    4.31 +        fd_set readfds;
    4.32          
    4.33 -        Move move;
    4.34 -        switch (code) {
    4.35 -        case NETCODE_TIMEOVER:
    4.36 -            printw("\rYour opponent's time ran out - you win!");
    4.37 -            clrtoeol();
    4.38 -            return 1;
    4.39 -        case NETCODE_SURRENDER:
    4.40 -            printw("\rYour opponent surrendered!");
    4.41 -            clrtoeol();
    4.42 -            return 1;
    4.43 -        case NETCODE_REMIS:
    4.44 -            if (prompt_yesno(
    4.45 -                "\rYour opponent offers remis - do you accept")) {
    4.46 -                printw("\rRemis accepted!");
    4.47 +        FD_ZERO(&readfds);
    4.48 +        FD_SET(opponent, &readfds);
    4.49 +        timeout.tv_sec = 0;
    4.50 +        timeout.tv_usec = 1e5;
    4.51 +        
    4.52 +        int result = select(opponent+1, &readfds, NULL, NULL, &timeout);
    4.53 +        if (result == -1) {
    4.54 +            printw("\rCannot perform asynchronous network IO");
    4.55 +            cbreak(); getch();
    4.56 +            exit(EXIT_FAILURE);
    4.57 +        }
    4.58 +        if (result > 0) {
    4.59 +            uint32_t code = net_recieve_code(opponent);
    4.60 +
    4.61 +            Move move;
    4.62 +            switch (code) {
    4.63 +            case NETCODE_TIMEOVER:
    4.64 +                printw("\rYour opponent's time ran out - you win!");
    4.65                  clrtoeol();
    4.66 -                net_send_code(opponent, NETCODE_ACCEPT);
    4.67                  return 1;
    4.68 -            } else {
    4.69 -                net_send_code(opponent, NETCODE_DECLINE);
    4.70 -            }
    4.71 -            break;
    4.72 -        case NETCODE_MOVE:
    4.73 -            net_recieve_data(opponent, &move, sizeof(Move));
    4.74 -            if (validate_move(gamestate, &move)) {
    4.75 -                apply_move(gamestate, &move);
    4.76 -                if (move.check) {
    4.77 -                    net_send_code(opponent, NETCODE_CHECK);
    4.78 -                } else if (gamestate->checkmate) {
    4.79 -                    net_send_code(opponent, NETCODE_CHECKMATE);
    4.80 -                    printw("\rCheckmate!");
    4.81 +            case NETCODE_SURRENDER:
    4.82 +                printw("\rYour opponent surrendered!");
    4.83 +                clrtoeol();
    4.84 +                return 1;
    4.85 +            case NETCODE_REMIS:
    4.86 +                if (prompt_yesno(
    4.87 +                    "\rYour opponent offers remis - do you accept")) {
    4.88 +                    printw("\rRemis accepted!");
    4.89                      clrtoeol();
    4.90 -                    return 1;
    4.91 -                } else if (gamestate->stalemate) {
    4.92 -                    net_send_code(opponent, NETCODE_STALEMATE);
    4.93 -                    printw("\rStalemate!");
    4.94 -                    clrtoeol();
    4.95 +                    net_send_code(opponent, NETCODE_ACCEPT);
    4.96                      return 1;
    4.97                  } else {
    4.98 -                    net_send_code(opponent, NETCODE_ACCEPT);
    4.99 +                    net_send_code(opponent, NETCODE_DECLINE);
   4.100                  }
   4.101 -                return 0;
   4.102 -            } else {
   4.103 -                net_send_code(opponent, NETCODE_DECLINE);
   4.104 +                break;
   4.105 +            case NETCODE_MOVE:
   4.106 +                net_recieve_data(opponent, &move, sizeof(Move));
   4.107 +                if (validate_move(gamestate, &move)) {
   4.108 +                    apply_move(gamestate, &move);
   4.109 +                    if (move.check) {
   4.110 +                        net_send_code(opponent, NETCODE_CHECK);
   4.111 +                    } else if (gamestate->checkmate) {
   4.112 +                        net_send_code(opponent, NETCODE_CHECKMATE);
   4.113 +                        printw("\rCheckmate!");
   4.114 +                        clrtoeol();
   4.115 +                        return 1;
   4.116 +                    } else if (gamestate->stalemate) {
   4.117 +                        net_send_code(opponent, NETCODE_STALEMATE);
   4.118 +                        printw("\rStalemate!");
   4.119 +                        clrtoeol();
   4.120 +                        return 1;
   4.121 +                    } else {
   4.122 +                        net_send_code(opponent, NETCODE_ACCEPT);
   4.123 +                    }
   4.124 +                    return 0;
   4.125 +                } else {
   4.126 +                    net_send_code(opponent, NETCODE_DECLINE);
   4.127 +                }
   4.128              }
   4.129          }
   4.130      }
     5.1 --- a/src/main.c	Wed Apr 09 11:12:04 2014 +0200
     5.2 +++ b/src/main.c	Wed Apr 09 12:07:47 2014 +0200
     5.3 @@ -165,7 +165,7 @@
     5.4          return EXIT_SUCCESS;
     5.5      }    
     5.6      initscr();
     5.7 -    halfdelay(10);
     5.8 +    halfdelay(1);
     5.9      keypad(stdscr, TRUE);
    5.10      if (has_colors()) {
    5.11          start_color();
    5.12 @@ -181,8 +181,12 @@
    5.13      if (settings.singlemachine) {
    5.14          game_start_singlemachine(&settings);
    5.15      } else {
    5.16 -        return is_server(&settings) ?
    5.17 +        int exitcode = is_server(&settings) ?
    5.18              server_run(&settings) : client_run(&settings);
    5.19 +        
    5.20 +        if (exitcode != EXIT_SUCCESS) {
    5.21 +            cbreak(); getch();
    5.22 +        }
    5.23      }
    5.24  }
    5.25  
     6.1 --- a/src/network.c	Wed Apr 09 11:12:04 2014 +0200
     6.2 +++ b/src/network.c	Wed Apr 09 12:07:47 2014 +0200
     6.3 @@ -29,6 +29,7 @@
     6.4  
     6.5  #include <stdlib.h>
     6.6  #include <string.h>
     6.7 +#include <fcntl.h>
     6.8  #include "network.h"
     6.9  
    6.10  #define new_socket() socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    6.11 @@ -133,3 +134,21 @@
    6.12  void net_recieve_data(int socket, void *data, size_t len) {
    6.13      recv(socket, data, len, 0);
    6.14  }
    6.15 +
    6.16 +int net_setnonblocking(int socket, _Bool nonblocking) {
    6.17 +    int opts = fcntl(socket, F_GETFL);
    6.18 +	if (opts < 0) {
    6.19 +		return 1;
    6.20 +	}
    6.21 +    
    6.22 +    if (nonblocking) {
    6.23 +        opts |= O_NONBLOCK;
    6.24 +    } else {
    6.25 +        opts &= ~O_NONBLOCK;
    6.26 +    }
    6.27 +	if (fcntl(socket, F_SETFL, opts) < 0) {
    6.28 +		return 1;
    6.29 +	}
    6.30 +    
    6.31 +    return 0;
    6.32 +}
     7.1 --- a/src/network.h	Wed Apr 09 11:12:04 2014 +0200
     7.2 +++ b/src/network.h	Wed Apr 09 12:07:47 2014 +0200
     7.3 @@ -74,6 +74,7 @@
     7.4  uint8_t net_recieve_code(int socket);
     7.5  void net_recieve_data(int socket, void *data, size_t len);
     7.6  
     7.7 +int net_setnonblocking(int socket, _Bool nonblocking);
     7.8  
     7.9  #ifdef	__cplusplus
    7.10  }
     8.1 --- a/src/server.c	Wed Apr 09 11:12:04 2014 +0200
     8.2 +++ b/src/server.c	Wed Apr 09 12:07:47 2014 +0200
     8.3 @@ -35,12 +35,12 @@
     8.4      printw("\nListening for client...\n");
     8.5      refresh();
     8.6      if (net_create(server, port)) {
     8.7 -        perror("Server creation failed");
     8.8 +        addstr("Server creation failed");
     8.9          return 1;
    8.10      }
    8.11  
    8.12      if (net_listen(server)) {
    8.13 -        perror("Listening for client failed");
    8.14 +        addstr("Listening for client failed");
    8.15          return 1;
    8.16      }
    8.17      
    8.18 @@ -50,7 +50,7 @@
    8.19  static int server_handshake(Client *client) {
    8.20      net_send_code(client->fd, NETCODE_VERSION);
    8.21      if (net_recieve_code(client->fd) != NETCODE_VERSION) {
    8.22 -        fprintf(stderr, "Client uses an incompatible software version.\n");
    8.23 +        addstr("Client uses an incompatible software version.");
    8.24          return 1;
    8.25      }
    8.26  
    8.27 @@ -90,7 +90,9 @@
    8.28          printw("\rClient connected - challenge declined.");
    8.29          clrtoeol();
    8.30      } else {
    8.31 -        fprintf(stderr, "Invalid client response\n");
    8.32 +        addstr("\rInvalid client response");
    8.33 +        clrtoeol();
    8.34 +        
    8.35          net_destroy(&server);
    8.36          return EXIT_FAILURE;
    8.37      }

mercurial