diff options
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; +} |