diff options
Diffstat (limited to 'pgm4/TTT.c')
-rw-r--r-- | pgm4/TTT.c | 590 |
1 files changed, 590 insertions, 0 deletions
diff --git a/pgm4/TTT.c b/pgm4/TTT.c new file mode 100644 index 0000000..373e44b --- /dev/null +++ b/pgm4/TTT.c @@ -0,0 +1,590 @@ +/* TTT.c + * + * I consulted the following pages to increase my understanding of servers that + * use select and to guide my thoughts of how I should construct my own server + * using the select function. + * http://www.binarytides.com/multiple-socket-connections-fdset-select-linux/ + * http://www.lowtek.com/sockets/select.html + * + * Utilizes code from P. Kearns - 1987, 2009 + * + * Adam Carpenter - 2017 + */ + +#include "ttt.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> +#include <arpa/inet.h> + +int checkEndGame(char *board) { + int i; + int tie = TRUE; + + // Check rows for win. + if (board[0] + board[1] + board[2] == 'X' + 'X' + 'X') return X_WIN; + else if (board[0] + board[1] + board[2] == 'O' + 'O' + 'O') return O_WIN; + if (board[3] + board[4] + board[5] == 'X' + 'X' + 'X') return X_WIN; + else if (board[3] + board[4] + board[5] == 'O' + 'O' + 'O') return O_WIN; + if (board[6] + board[7] + board[8] == 'X' + 'X' + 'X') return X_WIN; + else if (board[6] + board[7] + board[8] == 'O' + 'O' + 'O') return O_WIN; + + // Check columns for win. + if (board[0] + board[3] + board[6] == 'X' + 'X' + 'X') return X_WIN; + else if (board[0] + board[3] + board[6] == 'O' + 'O' + 'O') return O_WIN; + if (board[1] + board[4] + board[7] == 'X' + 'X' + 'X') return X_WIN; + else if (board[1] + board[4] + board[7] == 'O' + 'O' + 'O') return O_WIN; + if (board[2] + board[5] + board[8] == 'X' + 'X' + 'X') return X_WIN; + else if (board[2] + board[5] + board[8] == 'O' + 'O' + 'O') return O_WIN; + + // Check diagonals for win. + if (board[0] + board[4] + board[8] == 'X' + 'X' + 'X') return X_WIN; + else if (board[0] + board[4] + board[8] == 'O' + 'O' + 'O') return O_WIN; + if (board[2] + board[4] + board[6] == 'X' + 'X' + 'X') return X_WIN; + else if (board[2] + board[4] + board[6] == 'O' + 'O' + 'O') return O_WIN; + + // Check for tie win. + for (i = 0; i < 9; i++) { + if (board[i] != 'X' && board[i] != 'O') tie = FALSE; + } + + if (tie) { + return TIE_GAME; + } + + return 0; +} + +int main() { + int i; + char message[MESSAGE_BUFF]; + char hostname[MAX_HOSTNAME]; + int streamPort; + + int querySock; + int listenSock; + int newSock; + int connSockX; + int connSockO; + int queuedPlayers[MAX_CLIENTS]; + socklen_t length; + struct sockaddr_in *serverAddr, peerAddr; + struct addrinfo hints, *addrlist; + + int hits; + fd_set writeSockets; + fd_set readSockets; + + char gameBoard[] = "123456789"; + char handleX[MESSAGE_BUFF]; + char handleO[MESSAGE_BUFF]; + char gameTurn = 'X'; + int numPlayers = 0; + int gameOn = FALSE; + int winner = 0; + + int qPort = 0; + socklen_t qLength; + struct sockaddr_in *qServerAddr, from; + struct addrinfo qHints, *qAddrlist; + socklen_t fsize; + struct timeval timeout; + + // **** Create SOCK_DGRAM socket to send datagrams to clients **** + // Create qServerAddr for dgram. + memset(&qHints, 0, sizeof(qHints)); + qHints.ai_family = AF_INET; + qHints.ai_socktype = SOCK_DGRAM; + qHints.ai_flags = AI_NUMERICSERV | AI_PASSIVE; + qHints.ai_protocol = 0; + qHints.ai_canonname = NULL; + qHints.ai_addr = NULL; + qHints.ai_next = NULL; + + // Do getaddrinfo on qHints. + if (getaddrinfo(NULL, "0", &qHints, &qAddrlist) != 0) { + fprintf(stderr, "TTT: couldn't getaddrinfo for dgrams.\n"); + exit(1); + } + + // Set server address. + qServerAddr = (struct sockaddr_in *) qAddrlist->ai_addr; + + // Create socket. + if ((querySock = socket(qAddrlist->ai_family, qAddrlist->ai_socktype, 0)) < 0) { + fprintf(stderr, "TTT: couldn't create socket for dgrams.\n"); + exit(1); + } + + // Bind socket. + if (bind(querySock, (struct sockaddr *) qServerAddr, sizeof(struct sockaddr_in)) < 0) { + fprintf(stderr, "TTT: couldn't bind socket for dgrams.\n"); + exit(1); + } + + // Get the socket name for the querySock. + qLength = sizeof(struct sockaddr_in); + if (getsockname(querySock, (struct sockaddr *)qServerAddr, &qLength) < 0) { + fprintf(stderr, "TTT: couldn't get sock name for dgrams.\n"); + exit(1); + } + + qPort = ntohs(qServerAddr->sin_port); + timeout.tv_sec = 10; + timeout.tv_usec = 0; + setsockopt(querySock, SOL_SOCKET, SO_RCVTIMEO, (const char *) &timeout, sizeof(timeout)); + // ************************************************************* + + // **** Create SOCK_STREAM socket to listen for connections **** + // Create serverAddr for stream vc. + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE; + hints.ai_protocol = 0; + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + if (getaddrinfo(NULL, "0", &hints, &addrlist) != 0) { + fprintf(stderr, "TTT: couldn't getaddrinfo.\n"); + exit(1); + } + + // Set server address. + serverAddr = (struct sockaddr_in *) addrlist->ai_addr; + + // Create socket. + if ((listenSock = socket(addrlist->ai_family, addrlist->ai_socktype, 0)) < 0) { + fprintf(stderr, "TTT: couldn't create socket.\n"); + exit(1); + } + + // Bind socket. + if (bind(listenSock, (struct sockaddr *) serverAddr, sizeof(struct sockaddr_in)) < 0) { + fprintf(stderr, "TTT: couldn't bind socket.\n"); + exit(1); + } + + length = sizeof(struct sockaddr_in); + if (getsockname(listenSock, (struct sockaddr *)serverAddr, &length) < 0) { + fprintf(stderr, "TTT: couldn't get sock name.\n"); + exit(1); + } + + // Write ip and port numbers to game connection file. + FILE *addrFile; + + if (!(addrFile = fopen("prof.falken", "w"))) { + fprintf(stderr, "TTT: couldn't open file!\n"); + exit(1); + } + + if (gethostname(hostname, MAX_HOSTNAME) < 0) { + fprintf(stderr, "TTT: failed to get hostname.\n"); + exit(1); + } + + streamPort = ntohs(serverAddr->sin_port); + fprintf(addrFile, "%s\n", hostname); + fprintf(addrFile, "%d\n", streamPort); + fprintf(addrFile, "%d\n", qPort); + fclose(addrFile); + freeaddrinfo(addrlist); + + listen(listenSock, 6); + length = sizeof(peerAddr); + + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + + for (i = 0; i < MAX_CLIENTS; i++) { + queuedPlayers[i] = 0; + } + + // **** Main server loop **** + for (;;) { + // Set up select sockets. + FD_ZERO(&readSockets); + FD_SET(listenSock, &readSockets); + FD_ZERO(&writeSockets); + FD_SET(querySock, &readSockets); + + if (connSockX != 0) { + FD_SET(connSockX, &writeSockets); + FD_SET(connSockX, &readSockets); + } + + if (connSockO != 0) { + FD_SET(connSockO, &writeSockets); + FD_SET(connSockO, &readSockets); + } + + for (i = 0; i < MAX_CLIENTS; i++) { + if (queuedPlayers[i] > 0) { + if (queuedPlayers[i] != 0) { + FD_SET(queuedPlayers[i], &writeSockets); + } + } + } + + // Select sockets that need attention. + if ((hits = select(FD_SETSIZE, &readSockets, &writeSockets, NULL, NULL)) < 0) { + fprintf(stderr, "TTT: select failed.\n"); + exit(1); + } + + // Handle query requests. + if (FD_ISSET(querySock, &readSockets)) { + fsize = sizeof(from); + recvfrom(querySock, message, MESSAGE_BUFF, 0, (struct sockaddr *) &from, &fsize); + + if (gameOn == TRUE) { + strcpy(message, "Game in session between "); + strcat(message, handleX); + strcat(message, " and "); + strcat(message, handleO); + strcat(message, "\n"); + } + else { + strcpy(message, "No game in session...\n"); + + if (queuedPlayers[0] != 0) { + strcat(message, "Players waiting to play:\n"); + strcat(message, handleX); + strcat(message, "\n"); + } + else { + strcat(message, "No players waiting to play.\n"); + } + } + + strcat(message, "\0"); + sendto(querySock, message, MESSAGE_BUFF, 0, (struct sockaddr *) &from, sizeof(struct sockaddr_in)); + } + + // Handle new incoming connections. + if (FD_ISSET(listenSock, &readSockets)) { + + if ((newSock = accept(listenSock, (struct sockaddr *) &peerAddr, &length)) < 0) { + fprintf(stderr, "TTT: couldn't accept socket.\n"); + exit(1); + } + + // Queue up player. + for (i = 0; i < MAX_CLIENTS; i++) { + if (queuedPlayers[i] == 0 && newSock != 0) { + queuedPlayers[i] = newSock; + newSock = 0; + } + } + + newSock = 0; + } + + // **** Game logic **** + if (numPlayers == 0) { // Get first opponent. + + if (queuedPlayers[0] != 0) { + // Pull most recent client to be X + connSockX = queuedPlayers[0]; + + for (i = 1; i < MAX_CLIENTS; i++) { + queuedPlayers[i - 1] = queuedPlayers[i]; + } + + queuedPlayers[MAX_CLIENTS] = 0; + if (sendMessage(connSockX, HANDLE) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + if (getMessage(connSockX, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + else { + strcpy(handleX, message); + numPlayers++; + } + + } + + } + else if (numPlayers == 1) { // Get second opponent. + + if (queuedPlayers[0] != 0) { + // Pull most recent client to be O + connSockO = queuedPlayers[0]; + + for (i = 1; i < MAX_CLIENTS; i++) { + queuedPlayers[i - 1] = queuedPlayers[i]; + } + + queuedPlayers[MAX_CLIENTS] = 0; + if (sendMessage(connSockO, HANDLE) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + if (getMessage(connSockO, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + else { + strcpy(handleO, message); + numPlayers++; + } + + } + + } + else if (numPlayers == 2 && gameOn == FALSE) { // Set up a new game. + + if (FD_ISSET(connSockX, &writeSockets) && FD_ISSET(connSockO, &writeSockets)) { + // If both clients are ready, inform them of opponents and sides. + strcpy(message, "p X O "); + strcat(message, handleO); + if (sendMessage(connSockX, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + strcpy(message, "p O X "); + strcat(message, handleX); + if (sendMessage(connSockO, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + strcpy(gameBoard, "123456789"); + gameTurn = 'X'; + gameOn = TRUE; + } + + } + else if (numPlayers == 2 && gameOn == TRUE) { // Continue turn-taking. + + if (gameTurn == 'X' && FD_ISSET(connSockX, &writeSockets)) { + strcpy(message, "b "); + strcat(message, gameBoard); + if (sendMessage(connSockO, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } // send board to O + if (sendMessage(connSockO, WAIT) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } // tell O to wait for X to play + if (sendMessage(connSockX, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } // send board to X + if (sendMessage(connSockX, MOVE) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } // tell X to make a move + if (getMessage(connSockX, gameBoard)) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } // get move from X + gameTurn = 'O'; + + // Check for endgame. + winner = checkEndGame(gameBoard); + if (winner) { + strcpy(message, "b "); + strcat(message, gameBoard); + if (sendMessage(connSockX, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + if (sendMessage(connSockO, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + message[0] = ENDGAME; + message[1] = winner; + message[2] = '\0'; + if (sendMessage(connSockX, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + if (sendMessage(connSockO, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + + } + else if (gameTurn == 'O' && FD_ISSET(connSockO, &writeSockets)) { + strcpy(message, "b "); + strcat(message, gameBoard); + if (sendMessage(connSockX, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } // send board to X + if (sendMessage(connSockX, WAIT) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } // tell X to wait for O to play + if (sendMessage(connSockO, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } // send board to O + if (sendMessage(connSockO, MOVE) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } // tell O to make a move + if (getMessage(connSockO, gameBoard) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } // get move from O + gameTurn = 'X'; + + // Check for endgame. + winner = checkEndGame(gameBoard); + if (winner) { + strcpy(message, "b "); + strcat(message, gameBoard); + if (sendMessage(connSockX, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + if (sendMessage(connSockO, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + message[0] = ENDGAME; + message[1] = winner; + message[2] = '\0'; + if (sendMessage(connSockX, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + if (sendMessage(connSockO, message) == -1) { + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + numPlayers = 0; + handleX[0] = '\0'; + handleO[0] = '\0'; + connSockX = 0; + connSockO = 0; + gameOn = FALSE; + } + + } + + } + + } + + exit(0); +} |