diff options
Diffstat (limited to 'pgm4/ttt.c')
| -rw-r--r-- | pgm4/ttt.c | 257 | 
1 files changed, 257 insertions, 0 deletions
| diff --git a/pgm4/ttt.c b/pgm4/ttt.c new file mode 100644 index 0000000..572c588 --- /dev/null +++ b/pgm4/ttt.c @@ -0,0 +1,257 @@ +/* ttt.c + * + * Utilizes code from P. Kearns - 1987, 2009 + * Adam Carpenter - 2017 + */ + +#include "ttt.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> + +int main(int argc, char *argv[]) { +    int queryFlag; +    struct timeval timeout; +    int i; +    int errno; +    int hits; +    fd_set readSockets; +    // fd_set writeSockets; + +    char message[MESSAGE_BUFF]; +    char playerHandle[MESSAGE_BUFF]; +    char opponentHandle[MESSAGE_BUFF]; +    char playerSide; +    char opponentSide; +    char gameBoard[9]; +    char playerMove; +    int connSock; + +    char hostname[MAX_HOSTNAME]; +    char port[100]; +    struct sockaddr_in *serverAddr; +    struct addrinfo hints, *addrlist; + +    i = 1; +    queryFlag = FALSE; +    timeout.tv_sec = 0; +    timeout.tv_usec = 0; + +    while (argv[i]) { + +        if (strcmp(argv[i], "-q") == 0) { +            queryFlag = TRUE; +        } +        else if (strcmp(argv[i], "-t") == 0) { + +            if (!argv[i + 1]) { +                fprintf(stderr, "usage: ./ttt {-q} {-t} [timeout]\n"); +                exit(1); +            } + +            timeout.tv_sec = strtol(argv[i + 1], NULL, 10); +            errno = 0; + +            if (timeout.tv_sec <= 0) { +                fprintf(stderr, "ttt: timeout must be a positive, nonzero integer.\n"); +                exit(1); +            } +            else if (errno == ERANGE) { +                fprintf(stderr, "ttt: timeout must be of integer size.\n"); +                exit(1); +            } +            else if (errno == EINVAL) { +                fprintf(stderr, "ttt: timeout must be integer type.\n"); +                exit(1); +            } + +            i++; +        } +        else { +            fprintf(stderr, "usage: ./ttt {-q} {-t} [timeout]\n"); +            exit(1); +        } + +        i++; +    } + +    // Get server sockaddr. +    memset( &hints, 0, sizeof(hints)); +    hints.ai_family = AF_INET; + +    if (queryFlag) { +        hints.ai_socktype = SOCK_DGRAM; +    } +    else { +        hints.ai_socktype = SOCK_STREAM; + +    } + +    hints.ai_flags = AI_NUMERICSERV; +    hints.ai_protocol = 0; +    hints.ai_canonname = NULL; +    hints.ai_addr = NULL; +    hints.ai_next = NULL; + +    // (Read name and port from file.) +    FILE *addrfile; + +    if (!(addrfile = fopen("prof.falken", "r"))) { +        sleep(60); +        if (!(addrfile = fopen("prof.falken", "r"))) { +            fprintf(stderr, "ttt: couldn't open file -- is server running?\n"); +            exit(1); +        } +    } + +    fscanf(addrfile, "%s\n", hostname); +    fscanf(addrfile, "%s\n", port); + +    if (queryFlag) { +        fscanf(addrfile, "%s\n", port); +    } + +    fclose(addrfile); + +    if (getaddrinfo(hostname, port, &hints, &addrlist) != 0) { +        fprintf(stderr, "ttt: couldn't getaddrinfo.\n"); +        exit(1); +    } + +    serverAddr = (struct sockaddr_in *) addrlist->ai_addr; + +    if ((connSock = socket(addrlist->ai_family, addrlist->ai_socktype, 0)) < 0) { +        fprintf(stderr, "ttt: couldn't create socket.\n"); +        exit(1); +    } + +    if (queryFlag) { // Wait for query from server if requested. +        printf("Querying server...\n"); +        message[0] = '\0'; +        timeout.tv_sec = 10; +        timeout.tv_usec = 0; +        setsockopt(connSock, SOL_SOCKET, SO_RCVTIMEO, (const char *) &timeout, sizeof(timeout)); +        sendto(connSock, "q\0", strlen("q\0"), 0, (struct sockaddr *) serverAddr, sizeof(struct sockaddr_in)); +        recvfrom(connSock, message, MESSAGE_BUFF, 0, NULL, NULL); + +        if (message[0] == '\0') { +            printf("Connection timed out.\n"); +        } +        else { +            printf("%s\n", message); +        } + +        exit(0); +    } +    else { // Else connect to virtual circuit with server. +        if (connect(connSock, (struct sockaddr *) serverAddr, sizeof(struct sockaddr_in)) < 0) { +            fprintf(stderr, "ttt: couldn't connect to socket.\n"); +            exit(1); +        } +    } + +    printf("Waiting for server...\n"); +    playerHandle[0] = '\0'; + +    // Enter main client loop. +    for(;;) { +        FD_ZERO(&readSockets); +        FD_SET(connSock, &readSockets); + +        if (timeout.tv_sec == 0) { +            hits = select(FD_SETSIZE, &readSockets, NULL, NULL, NULL); +        } +        else { +            hits = select(FD_SETSIZE, &readSockets, NULL, NULL, &timeout); +        } + +        if (hits < 0) { +            fprintf(stderr, "ttt: failed to select.\n"); +            exit(1); +        } +        else if (hits == 0) { +            fprintf(stderr, "ttt: connection timed out.\n"); +            exit(0); +        } + +        // Get instructions from server. +        getMessage(connSock, message); + +        if (strcmp(message, HANDLE) == 0) { // Get and send handle. + +            if (playerHandle[0] == '\0') { +                printf("Who are you? "); +                scanf("%20[^\n]", playerHandle); +            } + +            sendMessage(connSock, playerHandle); +            printf("Waiting for opponent...\n"); +        } +        else if (strcmp(message, ABORT) == 0) { // Abort. +            printf("Server ordered shutdown. Buhbye!\n"); +            exit(0); +        } +        else if (message[0] == PLAYERID) { // Print name and sides. +            sscanf(message, "p %c %c %[^\n]", &playerSide, &opponentSide, opponentHandle); + +            if (playerSide == 'X') { +                opponentSide = 'O'; +            } +            else { +                opponentSide = 'X'; +            } + +            printf("%s, you are %cs. Your opponent %s is %cs.\n", playerHandle, playerSide, opponentHandle, opponentSide); +            timeout.tv_sec = 0; // Game established -- end timeout. +        } +        else if (message[0] == BOARD) { // Draw the game board. +            sscanf(message, "b %s", gameBoard); +            printf("\n %c | %c | %c\n-----------\n %c | %c | %c\n-----------\n %c | %c | %c\n\n", +                gameBoard[0], gameBoard[1], gameBoard[2], +                gameBoard[3], gameBoard[4], gameBoard[5], +                gameBoard[6], gameBoard[7], gameBoard[8]); +        } +        else if (strcmp(message, WAIT) == 0) { // Wait for opponent. +            printf("Waiting for opponent...\n"); +        } +        else if (strcmp(message, MOVE) == 0) { // Get and send move. +            playerMove = '0'; + +            while (playerMove < '1' ||  playerMove > '9' || gameBoard[playerMove - '0' - 1] != playerMove) { +                if (playerMove != '\n') { +                    printf("Choose an available number on the board.\nYour move: "); +                } + +                playerMove = getchar(); +            } + +            gameBoard[playerMove - '0' - 1] = playerSide; +            strcpy(message, gameBoard); +            sendMessage(connSock, message); +            printf("Waiting for opponent..."); +        } +        else if (message[0] == ENDGAME) { // End Game. + +            if (message[1] == playerSide) { +                printf("\nYou won %s! Congratulations!\n", playerHandle); +            } +            else if (message[1] == opponentSide) { +                printf("\nYou lost! %s won the match.\nBetter luck next time.\n", opponentHandle); +            } +            else { +                printf("\nThe match was a tie!\nBetter luck next time.\n"); +            } +            exit(0); +        } + +    } + +    exit(0); +} |