diff options
author | 53hornet <53hornet@gmail.com> | 2019-02-02 22:59:54 -0500 |
---|---|---|
committer | 53hornet <53hornet@gmail.com> | 2019-02-02 22:59:54 -0500 |
commit | 379c2c17e68d5d471a6a9673b7e9cd1fb9d99bbb (patch) | |
tree | eed499da8211a5eece757639331a2d82bce4fa4c /pgm4 | |
download | csci415-379c2c17e68d5d471a6a9673b7e9cd1fb9d99bbb.tar.xz csci415-379c2c17e68d5d471a6a9673b7e9cd1fb9d99bbb.zip |
Diffstat (limited to 'pgm4')
-rw-r--r-- | pgm4/TTT.c | 590 | ||||
-rw-r--r-- | pgm4/inet_addrs.d/Makefile | 10 | ||||
-rw-r--r-- | pgm4/inet_addrs.d/README | 11 | ||||
-rw-r--r-- | pgm4/inet_addrs.d/getaddrs.c | 171 | ||||
-rw-r--r-- | pgm4/inet_addrs.d/gethost.c | 57 | ||||
-rw-r--r-- | pgm4/inet_dgrams.d/Makefile | 17 | ||||
-rw-r--r-- | pgm4/inet_dgrams.d/README | 11 | ||||
-rw-r--r-- | pgm4/inet_dgrams.d/fancy_recv_udp.c | 117 | ||||
-rw-r--r-- | pgm4/inet_dgrams.d/recv_udp.c | 115 | ||||
-rw-r--r-- | pgm4/inet_dgrams.d/send_udp.c | 87 | ||||
-rw-r--r-- | pgm4/inet_streams.d/Makefile | 13 | ||||
-rw-r--r-- | pgm4/inet_streams.d/README | 3 | ||||
-rw-r--r-- | pgm4/inet_streams.d/inet_rstream.c | 110 | ||||
-rw-r--r-- | pgm4/inet_streams.d/inet_wstream.c | 91 | ||||
-rw-r--r-- | pgm4/makefile | 19 | ||||
-rw-r--r-- | pgm4/ttt.c | 257 | ||||
-rw-r--r-- | pgm4/ttt.h | 33 | ||||
-rw-r--r-- | pgm4/tttmsg.c | 55 |
18 files changed, 1767 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); +} diff --git a/pgm4/inet_addrs.d/Makefile b/pgm4/inet_addrs.d/Makefile new file mode 100644 index 0000000..a10866c --- /dev/null +++ b/pgm4/inet_addrs.d/Makefile @@ -0,0 +1,10 @@ +all: gethost getaddrs + +gethost: gethost.c + gcc -Wall -o gethost gethost.c + +getaddrs: getaddrs.c + gcc -Wall -o getaddrs getaddrs.c + +clean: + rm -f getaddrs gethost diff --git a/pgm4/inet_addrs.d/README b/pgm4/inet_addrs.d/README new file mode 100644 index 0000000..fbfb676 --- /dev/null +++ b/pgm4/inet_addrs.d/README @@ -0,0 +1,11 @@ +A pair of simple programs which play with symbolic and IP addresses. + +Invoke as: + getaddrs host service + host should be a symbolic host name + service should be a service name, port number, or 0 + + gethost ipaddr + ipaddr should be a dotted decimal IP address + + diff --git a/pgm4/inet_addrs.d/getaddrs.c b/pgm4/inet_addrs.d/getaddrs.c new file mode 100644 index 0000000..f229662 --- /dev/null +++ b/pgm4/inet_addrs.d/getaddrs.c @@ -0,0 +1,171 @@ +// Using getaddrinfo() to get IPv4 address for +// hostname (argv[1]) and service (argv[2]). +// +// The print_XXX() functions are from Stevens +// and Rago. +// +// P. Kearns, February 2009 + + +#include <netdb.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +void +print_family(struct addrinfo *aip) +{ + printf(" family "); + switch (aip->ai_family) { + case AF_INET: + printf("inet"); + break; + case AF_INET6: + printf("inet6"); + break; + case AF_UNIX: + printf("unix"); + break; + case AF_UNSPEC: + printf("unspecified"); + break; + default: + printf("unknown"); + } + +} +void +print_type(struct addrinfo *aip) +{ + printf(" type "); + switch (aip->ai_socktype) { + case SOCK_STREAM: + printf("stream"); + break; + case SOCK_DGRAM: + printf("datagram"); + break; + case SOCK_SEQPACKET: + printf("seqpacket"); + break; + case SOCK_RAW: + printf("raw"); + break; + default: + printf("unknown (%d)", aip->ai_socktype); + } +} + +void +print_protocol(struct addrinfo *aip) +{ + printf(" protocol "); + switch (aip->ai_protocol) { + case 0: + printf("default"); + break; + case IPPROTO_TCP: + printf("TCP"); + break; + case IPPROTO_UDP: + printf("UDP"); + break; + case IPPROTO_RAW: + printf("raw"); + break; + default: + printf("unknown (%d)", aip->ai_protocol); + } +} + +void +print_flags(struct addrinfo *aip) +{ + printf("flags"); + if (aip->ai_flags == 0) { + printf(" 0"); + + } else { + if (aip->ai_flags & AI_PASSIVE) + printf(" passive"); + if (aip->ai_flags & AI_CANONNAME) + printf(" canon"); + if (aip->ai_flags & AI_NUMERICHOST) + printf(" numhost"); +#if defined(AI_NUMERICSERV) + if (aip->ai_flags & AI_NUMERICSERV) + printf(" numserv"); +#endif +#if defined(AI_V4MAPPED) + if (aip->ai_flags & AI_V4MAPPED) + printf(" v4mapped"); +#endif +#if defined(AI_ALL) + if (aip->ai_flags & AI_ALL) + printf(" all"); +#endif + } +} + +int main(int argc,char **argv) +{ + struct addrinfo *addrlist, *aptr, hints; + struct sockaddr_in *saddrptr; + const char * p; char addrbuffer[INET_ADDRSTRLEN]; int ecode; + + if(argc != 3) { + fprintf(stderr, "usage: getaddrs node service\n"); + exit(1); + } + +// Want IPv4 lookup only. + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = 0; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = 0; + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + +// Do the lookup. + + ecode = getaddrinfo(argv[1], argv[2], &hints, &addrlist); + if (ecode != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ecode)); + exit(1); + } + +// Scan the list of results. + + for (aptr = addrlist; aptr != NULL; aptr = aptr->ai_next) { + print_flags(aptr); print_family(aptr); + print_type(aptr); print_protocol(aptr); + + if (aptr->ai_family == AF_INET){ + printf("\tName: %s\n", aptr->ai_canonname?aptr->ai_canonname:"none"); + + // Get at filled-in sockaddr_in hanging off the addrinfo. + + saddrptr = (struct sockaddr_in *) aptr->ai_addr; + p = inet_ntop(AF_INET, &saddrptr->sin_addr.s_addr, addrbuffer, INET_ADDRSTRLEN); + + if (!p) { + perror("inet_ntop"); + exit(1); + } + + printf("IP Address: %s\n", p?p:"unknown"); + printf("Port: %d\n", ntohs(saddrptr->sin_port)); + } + } + + // Give back result structs (not really impt here). + + freeaddrinfo(addrlist); + exit(0); +} diff --git a/pgm4/inet_addrs.d/gethost.c b/pgm4/inet_addrs.d/gethost.c new file mode 100644 index 0000000..dcfc7fd --- /dev/null +++ b/pgm4/inet_addrs.d/gethost.c @@ -0,0 +1,57 @@ +// Using getnameinfo() to get host name for a +// given IP address (argv[1]). +// +// P. Kearns, February 2009 + +#include <netdb.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +int main(int argc, char **argv) +{ + + int ecode; + struct in_addr fillin; + struct sockaddr_in addr; + char host[NI_MAXHOST]; + + if (argc != 2) { + fprintf(stderr,"usage: gethost address\n"); + exit(1); + } + +// Dotted decimal to binary IP address. + + ecode = inet_pton(AF_INET, argv[1], &fillin); + if (ecode == 0) { + fprintf(stderr,"inet_pton: invalid address\n"); + exit(1); + } + if (ecode < 0) { + perror("inet_pton"); exit(1); + exit(1); + } + +// Fill in blanks of a sockaddr_in after zeroing it out. + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(0); + memcpy(&(addr.sin_addr), &fillin, sizeof(addr.sin_addr)); + +// Do the lookup. + + ecode = getnameinfo((struct sockaddr *) &addr, sizeof(addr), + host, NI_MAXHOST, NULL, 0, NI_NAMEREQD); + if (ecode) { + fprintf(stderr, "getnameinfo: %s\n", gai_strerror(ecode)); + exit(1); + } + + printf("Hostname: %s\n", host); + exit(0); +} diff --git a/pgm4/inet_dgrams.d/Makefile b/pgm4/inet_dgrams.d/Makefile new file mode 100644 index 0000000..14018f2 --- /dev/null +++ b/pgm4/inet_dgrams.d/Makefile @@ -0,0 +1,17 @@ +CC=gcc +CFLAGS=-g -Wall + +all: recv_udp send_udp fancy_recv_udp + +recv_udp: recv_udp.o + $(CC) -o recv_udp recv_udp.o + +fancy_recv_udp: fancy_recv_udp.o + $(CC) -o fancy_recv_udp fancy_recv_udp.o + +send_udp: send_udp.o + $(CC) -o send_udp send_udp.o + +clean: + rm -f *.o recv_udp send_udp fancy_recv_udp + diff --git a/pgm4/inet_dgrams.d/README b/pgm4/inet_dgrams.d/README new file mode 100644 index 0000000..d5bac0f --- /dev/null +++ b/pgm4/inet_dgrams.d/README @@ -0,0 +1,11 @@ +Some simple programs which do datagram-based message passing on the +Internet. + +----------- + +send_udp.c and recv_udp.c are the simple send/receive processes. + +send_udp.c and fancy_recv_udp.c implement the "fancy" receiver that + was described in lecture. + + diff --git a/pgm4/inet_dgrams.d/fancy_recv_udp.c b/pgm4/inet_dgrams.d/fancy_recv_udp.c new file mode 100644 index 0000000..bb4c20a --- /dev/null +++ b/pgm4/inet_dgrams.d/fancy_recv_udp.c @@ -0,0 +1,117 @@ +/*********************************************************************\ +* FANCY_RECV_UDP.C * +* Test of UDP/IP. Receive datagrams on internet socket bound to port * +* 0x3333 on the local host. * +* * +* To use: * +* 1) On the appropriate host, invoke this code by * +* "fancy_recv_udp&". * +* 2) Invoke send_udp as many times as desired on the * +* remote host. * +* * +* Phil Kearns * +* April 11, 1987 * +* * +* Modified: April 10, 1992 * +* responds to input (CR) on stdin by cleanly shutting down * +* also shuts down if no datagrams for a minute * +\*********************************************************************/ + +#include <signal.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <stdlib.h> + +void printsin(struct sockaddr_in*, char*, char*); + +int main() +{ + int socket_fd, cc, hits, ecode; + socklen_t fsize; + fd_set mask; + struct timeval timeout; + struct sockaddr_in *s_in, from; + struct addrinfo hints, *addrlist; + + struct { + char head; + u_long body; + char tail; + } msg; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE; hints.ai_protocol = 0; + hints.ai_canonname = NULL; hints.ai_addr = NULL; + hints.ai_next = NULL; + + ecode = getaddrinfo(NULL, "13107", &hints, &addrlist); + if (ecode != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ecode)); + exit(1); + } + + s_in = (struct sockaddr_in *) addrlist->ai_addr; + + printsin(s_in, "FANCY_RECV_UDP", "Local socket is:"); fflush(stdout); + + + socket_fd = socket (addrlist->ai_family, addrlist->ai_socktype, 0); + if (socket_fd < 0) { + perror ("fancy_recv_udp:socket"); + exit (1); + } + +/* + bind port 0x3333 on the current host to the socket accessed through + socket_fd. If port in use, die. +*/ + if (bind(socket_fd, (struct sockaddr *)s_in, sizeof(struct sockaddr_in)) < 0) { + perror("fancy_recv_udp:bind"); + exit(1); + } + + for(;;) { + fsize = sizeof(from); +/* Here's the new stuff. Hang a select on the file descriptors 0 (stdin) + and socket_fd looking to see if either descriptor is able to be read. + If it's stdin, shut down. If it's socket_fd, proceed as normal. If + Nothing happens for a minute, shut down also. +*/ + FD_ZERO(&mask); + FD_SET(0,&mask); + FD_SET(socket_fd,&mask); + timeout.tv_sec = 60; + timeout.tv_usec = 0; + if ((hits = select(socket_fd+1, &mask, (fd_set *)0, (fd_set *)0, + &timeout)) < 0) { + perror("fancy_recv_udp:select"); + exit(1); + } + if ( (hits==0) || ((hits>0) && (FD_ISSET(0,&mask))) ) { + printf("Shutting down\n"); + exit(0); + } + cc = recvfrom(socket_fd,&msg,sizeof(msg),0,(struct sockaddr *)&from,&fsize); + if (cc < 0) perror("recv_udp:recvfrom"); + printsin( &from, "recv_udp: ", "Packet from:"); + printf("Got data ::%c%u%c\n",msg.head,ntohl(msg.body),msg.tail); + fflush(stdout); + } + exit(0); +} + +void printsin(struct sockaddr_in *sin, char *m1, char *m2 ) +{ + char fromip[INET_ADDRSTRLEN]; + + printf ("%s %s:\n", m1, m2); + printf (" family %d, addr %s, port %d\n", sin -> sin_family, + inet_ntop(AF_INET, &(sin->sin_addr.s_addr), fromip, sizeof(fromip)), + ntohs((unsigned short)(sin -> sin_port))); +} diff --git a/pgm4/inet_dgrams.d/recv_udp.c b/pgm4/inet_dgrams.d/recv_udp.c new file mode 100644 index 0000000..24c47b5 --- /dev/null +++ b/pgm4/inet_dgrams.d/recv_udp.c @@ -0,0 +1,115 @@ +/*********************************************************************\ +* RECV_UDP.C * +* Test of UDP/IP. Receive datagrams on internet socket bound to port * +* 0x3333 on the local host. * +* * +* To use: * +* 1) On the appropriate host, invoke this code by * +* "recv_udp&". * +* 2) Invoke send_udp as many times as desired on the * +* remote host. * +* 3) When done, MAKE SURE TO KILL THIS BACKGROUND PROCESS! * +* * +* Phil Kearns * +* April 11, 1987 * +* * +* Modified February 2009: use getaddrinfo() * +\*********************************************************************/ + +#include <stdlib.h> +#include <signal.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <arpa/inet.h> + +void printsin(struct sockaddr_in*, char*, char*); + +int main() +{ + int socket_fd, cc, ecode; + socklen_t fsize; + struct sockaddr_in *s_in, from; + struct addrinfo hints, *addrlist; + void printsin(); + + struct { + char head; + u_long body; + char tail; + } msg; + +/* + In order to attach a name to the socket created above, first fill + in the appropriate blanks in an inet socket address data structure + called "s_in". We blindly pick port number 0x3333. The second step + is to BIND the address to the socket. If port 0x3333 is in use, the + bind system call will fail detectably. +*/ + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICSERV | AI_PASSIVE; hints.ai_protocol = 0; + hints.ai_canonname = NULL; hints.ai_addr = NULL; + hints.ai_next = NULL; + +/* + getaddrinfo() should return a single result, denoting + a SOCK_DGRAM socket on any interface of this system at + port 0x3333. +*/ + + ecode = getaddrinfo(NULL, "13107", &hints, &addrlist); + if (ecode != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ecode)); + exit(1); + } + + s_in = (struct sockaddr_in *) addrlist->ai_addr; + + printsin(s_in, "RECV_UDP", "Local socket is:"); fflush(stdout); + +/* + Create the socket to be used for datagram reception. Initially, + it has no name in the internet (or any other) domain. +*/ + socket_fd = socket (addrlist->ai_family, addrlist->ai_socktype, 0); + if (socket_fd < 0) { + perror ("recv_udp:socket"); + exit (1); + } + +/* + bind port 0x3333 on the current host to the socket accessed through + socket_fd. If port in use, bind() will fail and we die. +*/ + + if (bind(socket_fd, (struct sockaddr *)s_in, sizeof(struct sockaddr_in)) < 0) { + perror("recv_udp:bind"); + exit(1); + } + + for(;;) { + fsize = sizeof(from); + cc = recvfrom(socket_fd, &msg, sizeof(msg), 0, (struct sockaddr *)&from, &fsize); + if (cc < 0) perror("recv_udp:recvfrom"); + printsin( &from, "recv_udp: ", "Packet from:"); + printf("Got data ::%c%u%c\n",msg.head,ntohl(msg.body),msg.tail); + fflush(stdout); + } + exit(0); +} + +void printsin(struct sockaddr_in *sin, char *m1, char *m2 ) +{ + char fromip[INET_ADDRSTRLEN]; + + printf ("%s %s:\n", m1, m2); + printf (" family %d, addr %s, port %d\n", sin -> sin_family, + inet_ntop(AF_INET, &(sin->sin_addr.s_addr), fromip, sizeof(fromip)), + ntohs((unsigned short)(sin -> sin_port))); +} diff --git a/pgm4/inet_dgrams.d/send_udp.c b/pgm4/inet_dgrams.d/send_udp.c new file mode 100644 index 0000000..63a3c96 --- /dev/null +++ b/pgm4/inet_dgrams.d/send_udp.c @@ -0,0 +1,87 @@ +/***********************************************************************\ +* SEND_UDP.C * +* Test of UDP/IP. Send a single dippy datagram to a receiver process * +* assumed to exist on port 0x3333 on the internet host specified as * +* the single argument to this program. * +* * +* To use: * +* 1) Make sure that recv_udp is running (probably in the * +* background on the target host. * +* 2) Issue the command "send_udp xx", where xx is a host name. * +* * +* Phil Kearns * +* April 11, 1987 * +* * +* Modified February 2009: use getaddrinfo() * +\***********************************************************************/ + +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> + +int main(int argc,char **argv) +{ + int socket_fd, cc, ecode; + struct sockaddr_in *dest; + struct addrinfo hints, *addrlist; + struct { + char head; + u_long body; + char tail; + } msgbuf; + + +/* + Use getaddrinfo to create a SOCK_DGRAM sockarddr_in set + up for the host specified as argv[1] and port 0x3333. +*/ + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICSERV; hints.ai_protocol = 0; + hints.ai_canonname = NULL; hints.ai_addr = NULL; + hints.ai_next = NULL; + + ecode = getaddrinfo(argv[1], "13107", &hints, &addrlist); + if (ecode != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ecode)); + exit(1); + } + + dest = (struct sockaddr_in *) addrlist->ai_addr; // Will use in sendto(). + +/* + Set up a datagram (UDP/IP) socket in the Internet domain. + We will use it as the handle thru which we will send a + single datagram. Note that, since this no message is ever + addressed TO this socket, we do not bind an internet address + to it. It will be assigned a (temporary) address when we send + a message thru it. +*/ + + socket_fd = socket (addrlist->ai_family, addrlist->ai_socktype, 0); + if (socket_fd == -1) { + perror ("send_udp:socket"); + exit (1); + } + + msgbuf.head = '<'; + msgbuf.body = htonl(getpid()); + msgbuf.tail = '>'; + + cc = sendto(socket_fd,&msgbuf,sizeof(msgbuf),0,(struct sockaddr *) dest, + sizeof(struct sockaddr_in)); + if (cc < 0) { + perror("send_udp:sendto"); + exit(1); + } + + exit(0); +} diff --git a/pgm4/inet_streams.d/Makefile b/pgm4/inet_streams.d/Makefile new file mode 100644 index 0000000..72c101d --- /dev/null +++ b/pgm4/inet_streams.d/Makefile @@ -0,0 +1,13 @@ +CC=gcc +CFLAGS=-g -Wall + +all: inet_rstream inet_wstream + +inet_rstream: inet_rstream.o + $(CC) -o inet_rstream inet_rstream.o + +inet_wstream: inet_wstream.o + $(CC) -o inet_wstream inet_wstream.o + +clean: + rm -f *.o inet_rstream inet_wstream diff --git a/pgm4/inet_streams.d/README b/pgm4/inet_streams.d/README new file mode 100644 index 0000000..ecbe3dc --- /dev/null +++ b/pgm4/inet_streams.d/README @@ -0,0 +1,3 @@ +A pair of simple programs which interact via a virtual circuit on +the Internet. + diff --git a/pgm4/inet_streams.d/inet_rstream.c b/pgm4/inet_streams.d/inet_rstream.c new file mode 100644 index 0000000..3dafee6 --- /dev/null +++ b/pgm4/inet_streams.d/inet_rstream.c @@ -0,0 +1,110 @@ +/************************************************************************\ +* INET_RSTREAM.C * +* Test of TCP/IP. Set up a socket for establishing a connection at * +* some free port on the local host. After accepting a connection, speak * +* briefly to peer, and then read char at a time from the stream. Write * +* to stdout. At EOF, shut down. * +* * +* Phil Kearns * +* April 11, 1987 * +* * +* Modified February 2009 to use getaddrinfo() * +\************************************************************************/ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +void printsin(struct sockaddr_in*, char*, char*); + +int main() +{ + int listener; /* fd for socket on which we get connection requests */ + int conn; /* fd for socket thru which we pass data */ + struct sockaddr_in *localaddr, peer; + int ecode; + socklen_t length; + char ch; + struct addrinfo hints, *addrlist; + + +/* + Want to specify local server address of: + addressing family: AF_INET + ip address: any interface on this system + port: 0 => system will pick free port +*/ + + 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; + + ecode = getaddrinfo(NULL, "0", &hints, &addrlist); + if (ecode != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ecode)); + exit(1); + } + + localaddr = (struct sockaddr_in *) addrlist->ai_addr; + +/* + Create socket on which we will accept connections. This is NOT the + same as the socket on which we pass data. +*/ + if ( (listener = socket( addrlist->ai_family, addrlist->ai_socktype, 0 )) < 0 ) { + perror("inet_rstream:socket"); + exit(1); + } + + + if (bind(listener, (struct sockaddr *)localaddr, sizeof(struct sockaddr_in)) < 0) { + perror("inet_rstream:bind"); + exit(1); + } + +/* + Print out the port number assigned to this process by bind(). +*/ + length = sizeof(struct sockaddr_in); + if (getsockname(listener, (struct sockaddr *)localaddr, &length) < 0) { + perror("inet_rstream:getsockname"); + exit(1); + } + printf("RSTREAM:: assigned port number %d\n", ntohs(localaddr->sin_port)); + +/* + Now accept a single connection. Upon connection, data will be + passed through the socket on descriptor conn. +*/ + listen(listener,1); + length = sizeof(peer); + if ((conn=accept(listener, (struct sockaddr *)&peer, &length)) < 0) { + perror("inet_rstream:accept"); + exit(1); + } + printsin(&peer,"RSTREAM::", "accepted connection from"); + + printf("\n\nRSTREAM:: data from stream:\n"); + while ( read(conn, &ch, 1) == 1) + putchar(ch); + putchar('\n'); + exit(0); +} + +void printsin(struct sockaddr_in *sin, char *m1, char *m2 ) +{ + char fromip[INET_ADDRSTRLEN]; + + printf ("%s %s:\n", m1, m2); + printf (" family %d, addr %s, port %d\n", sin -> sin_family, + inet_ntop(AF_INET, &(sin->sin_addr.s_addr), fromip, sizeof(fromip)), + ntohs((unsigned short)(sin -> sin_port))); +} diff --git a/pgm4/inet_streams.d/inet_wstream.c b/pgm4/inet_streams.d/inet_wstream.c new file mode 100644 index 0000000..8dcd284 --- /dev/null +++ b/pgm4/inet_streams.d/inet_wstream.c @@ -0,0 +1,91 @@ +/************************************************************************\ +* INET_WSTREAM.C * +* Test of TCP/IP. Invoke as * +* inet_wstream hostname portnumber * +* in order to send a fragment of an obnoxious Dijkstra quote to a * +* process assumed to be reading from a stream at the specified * +* address. * +* * +* Phil Kearns * +* April 11, 1987 * +* * +* Modified February 2009 to use getaddrinfo() * +\************************************************************************/ + +#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> + +char msg[] = { "false pearls before real swine" }; + +int main(argc, argv) +int argc; +char **argv; +{ + int sock, left, num, put, ecode; + struct sockaddr_in *server; + struct addrinfo hints, *addrlist; + + if (argc != 3) { + fprintf(stderr,"inet_wstream:usage is inet_wstream host port\n"); + exit(1); + } + + + +/* + Want a sockaddr_in containing the ip address for the system + specified in argv[1] and the port specified in argv[2]. +*/ + + memset( &hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; 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; + + ecode = getaddrinfo(argv[1], argv[2], &hints, &addrlist); + if (ecode != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ecode)); + exit(1); + } + + server = (struct sockaddr_in *) addrlist->ai_addr; + +/* + Create the socket. +*/ + if ( (sock = socket( addrlist->ai_family, addrlist->ai_socktype, 0 )) < 0 ) { + perror("inet_wstream:socket"); + exit(1); + } + +/* + Connect to data socket on the peer at the specified Internet + address. +*/ + if ( connect(sock, (struct sockaddr *)server, sizeof(struct sockaddr_in)) < 0) { + perror("inet_wstream:connect"); + exit(1); + } + +/* + Write the quote and terminate. This will close the connection on + this end, so eventually an "EOF" will be detected remotely. +*/ + left = sizeof(msg); put=0; + while (left > 0){ + if((num = write(sock, msg+put, left)) < 0) { + perror("inet_wstream:write"); + exit(1); + } + else left -= num; + put += num; + } + exit(0); +} diff --git a/pgm4/makefile b/pgm4/makefile new file mode 100644 index 0000000..645618f --- /dev/null +++ b/pgm4/makefile @@ -0,0 +1,19 @@ +all: tttmsg.o ttt.o TTT.o ttt TTT + +tttmsg.o: tttmsg.c + gcc -Wall -g -c tttmsg.c + +ttt.o: ttt.c + gcc -Wall -g -c ttt.c + +TTT.o: TTT.c + gcc -Wall -g -c TTT.c + +ttt: ttt.c + gcc -Wall -o ttt ttt.o tttmsg.o + +TTT: TTT.c + gcc -Wall -o TTT TTT.o tttmsg.o + +clean: + rm -f ttt TTT tttmsg.o ttt.o TTT.o 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); +} diff --git a/pgm4/ttt.h b/pgm4/ttt.h new file mode 100644 index 0000000..abc4c09 --- /dev/null +++ b/pgm4/ttt.h @@ -0,0 +1,33 @@ +/* ttt.h + * + * Adam Carpenter - 2017 + */ + +#ifndef TTT_H +#define TTT_H + + +// Constants. +#define MESSAGE_BUFF 64 +#define MAX_HOSTNAME 255 +#define MAX_CLIENTS 4 +#define FALSE 0 +#define TRUE 1 +#define X_WIN 'X' +#define O_WIN 'O' +#define TIE_GAME '-' + +// Messages that can be sent by the server and client. +#define HANDLE "h" +#define ABORT "a" +#define PLAYERID 'p' +#define BOARD 'b' +#define MOVE "m" +#define WAIT "w" +#define ENDGAME 'e' + +#endif + +// Function declarations. +int sendMessage(int connSock, char *message); +int getMessage(int connSock, char *message); diff --git a/pgm4/tttmsg.c b/pgm4/tttmsg.c new file mode 100644 index 0000000..d5ffb55 --- /dev/null +++ b/pgm4/tttmsg.c @@ -0,0 +1,55 @@ +/* tttmsg.c + * + * Adam Carpenter - 2017 + */ + + +#include "ttt.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +int sendMessage(int connSock, char *message) { + int left, num, put; + left = MESSAGE_BUFF; + put = 0; + + while (left > 0) { + + if ((num = write(connSock, message + put, left)) < 0) { + // fprintf(stderr, "ttt/TTT: couldn't send message!\n"); + perror("ttt/TTT: couldn't send message because "); + exit(1); + } + else if (num == 0) { + return -1; + } + else { + left -= num; + } + + put += num; + } + + return 0; +} + +int getMessage(int connSock, char *message) { + char ch; + int i = 0; + int num; + + for(i = 0; i < MESSAGE_BUFF; i++) { + + if ((num = read(connSock, &ch, 1)) < 0) { + fprintf(stderr, "ttt/TTT: couldn't receive message!\n"); + } + else if (num == 0) { + return -1; + } + + message[i] = ch; + } + + return 0; +} |