summaryrefslogtreecommitdiff
path: root/pgm4
diff options
context:
space:
mode:
Diffstat (limited to 'pgm4')
-rw-r--r--pgm4/TTT.c590
-rw-r--r--pgm4/inet_addrs.d/Makefile10
-rw-r--r--pgm4/inet_addrs.d/README11
-rw-r--r--pgm4/inet_addrs.d/getaddrs.c171
-rw-r--r--pgm4/inet_addrs.d/gethost.c57
-rw-r--r--pgm4/inet_dgrams.d/Makefile17
-rw-r--r--pgm4/inet_dgrams.d/README11
-rw-r--r--pgm4/inet_dgrams.d/fancy_recv_udp.c117
-rw-r--r--pgm4/inet_dgrams.d/recv_udp.c115
-rw-r--r--pgm4/inet_dgrams.d/send_udp.c87
-rw-r--r--pgm4/inet_streams.d/Makefile13
-rw-r--r--pgm4/inet_streams.d/README3
-rw-r--r--pgm4/inet_streams.d/inet_rstream.c110
-rw-r--r--pgm4/inet_streams.d/inet_wstream.c91
-rw-r--r--pgm4/makefile19
-rw-r--r--pgm4/ttt.c257
-rw-r--r--pgm4/ttt.h33
-rw-r--r--pgm4/tttmsg.c55
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;
+}