summaryrefslogtreecommitdiff
path: root/pgm4/TTT.c
diff options
context:
space:
mode:
Diffstat (limited to 'pgm4/TTT.c')
-rw-r--r--pgm4/TTT.c590
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);
+}