/* ttt.c * * Utilizes code from P. Kearns - 1987, 2009 * Adam Carpenter - 2017 */ #include "ttt.h" #include #include #include #include #include #include #include #include #include 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); }