// server.c -- open an internet socket and use it to accept a client. /* Derived from isockl.c (C) 1991 Blair P. Houghton, All Rights Reserved, copying and distribution permitted with copyright intact. Modified in 1993 to remove pre-ANSI code by Michael J. Fischer Modified 2010 to improve style and clarity by Michael J. Fischer and Alice E. Fischer */ #include "tools.h" // Shorter names for system structures typedef struct sockaddr_in sockInfo; typedef struct sockaddr sockUnion; typedef struct hostent hostInfo; // ----------------------------------------------------------------------------- // Prototypes int openWelcomeSocket(int requestedPort); void getWelcomeInfo(int welcomeFd, char* localName, int localNameSize, int* localPort); void acceptConnection(int welcomeFd, FILE** peerIn, FILE** peerOut); void printSockInfo(char* who, sockInfo sock); // ----------------------------------------------------------------------------- // arg 1 is port number of listener. 0 means to assign a port int main(int argc, char *argv[]) { char buf[BUFSIZ + 1]; int status; char* ret; FILE* peerIn; FILE* peerOut; char localName[256]; // name of local host. const int localNameSize = sizeof localName; int localPort; // collect command line arguments const char* prog = argv[0]; if (argc != 2) fatal("usage: %s portno\n", prog); int requestedPort = atoi(argv[1]); // open a welcome socket on the requested port int welcomeFd = openWelcomeSocket(requestedPort); // get information about the welcome socket getWelcomeInfo(welcomeFd, localName, localNameSize, &localPort); // print out info printf("Server is listening on socket %s %d\n", localName, localPort); // accept connection from peer acceptConnection(welcomeFd, &peerIn, &peerOut); // tell client the connection is OK. status = fprintf(peerOut, "Connected to (%s.%d)\n", localName, localPort); if (status < 2) fatalp("Failed to write into socket."); fflush(peerOut); sleep(3); printf("Entering read loop\n"); // read lines until the stream closes -------------------------------------- // buf is BUFSIZ+1 to allow for a null terminator. for (;;) { ret = fgets(buf, BUFSIZ, peerIn); if (!ret) break; // end of transmission printf("Read from socket: %s", buf); } // clean up and exit status = fclose(peerIn); if (status) fatalp("Error closing input stream on socket"); status = fclose(peerOut); if (status) fatalp("Error closing output stream on socket"); printf("Server exiting\n"); exit(0); } // ----------------------------------------------------------------------------- // Open a welcome socket on requested port and return its file descriptor. // If requested port is 0, it chooses a port to listen on. int openWelcomeSocket(int requestedPort) { int status; // Make a net socket, using stream mode, with protocol irrelevant ( == 0 ) int welcomeFd = socket(AF_INET, SOCK_STREAM, 0); if (welcomeFd < 0) fatalp("Can't create socket"); // Create an address structure for the welcome socket sockInfo welcomeSock; welcomeSock.sin_family = AF_INET; // Address family internet welcomeSock.sin_port = htons(requestedPort); // Use requested port, if non-zero welcomeSock.sin_addr.s_addr = INADDR_ANY; // Accept connections from anybody. // Bind the network address structure to the new socket status = bind(welcomeFd, (sockUnion*) &welcomeSock, sizeof welcomeSock); if (status < 0) fatal("Can't bind socket (%d)", welcomeFd); // Wait for a client to come knock-knocking on the welcomeSocket. listen(welcomeFd, 1); // 1: only one queue slot return welcomeFd; } // ----------------------------------------------------------------------------- // Returns hostname of local host and port number of listener. // Bug: This routine should obtain the host name from the welcome // file descriptor, so that it would be useful to get information // from the peer socket as well. void getWelcomeInfo(int welcomeFd, char* localName, int localNameSize, int* localPort) { int status; sockInfo welcomeSock; // Find out what port number actually got assigned to the welcome socket. socklen_t addressLength = sizeof(welcomeSock); // might be changed by the call. status = getsockname(welcomeFd, (sockUnion*) &welcomeSock, &addressLength); if (status < 0) fatal("Can't get port # of socket (%d)", welcomeFd); *localPort = ntohs(welcomeSock.sin_port); // Find our own host name status = gethostname(localName, localNameSize); // name of local host. if (status) fatalp("Can't get host name of server"); // printf("opened socket on host %s as fd (%d) on port (%d) for stream i/o\n", // localName, welcomeFd, *localPort); // printSockInfo("server", welcomeSock); } // ----------------------------------------------------------------------------- void acceptConnection(int welcomeFd, FILE** peerIn, FILE** peerOut) { sockInfo peer; // properties for peer process // Accept a new incoming connection. socklen_t addressLength = sizeof(peer); // might be changed by the call. int peerFd = accept(welcomeFd, (sockUnion*) &peer, &addressLength); if (peerFd < 0) fatalp("Server failed to accept connection."); printSockInfo("Peer", peer); // Who is our peer? *peerOut = fdopen(peerFd, "w"); if (!peerOut) fatalp("Can't create output stream"); int peerFd2 = dup(peerFd); if (peerFd2 < 0) fatalp("Can't duplicate socket file descriptor"); * peerIn = fdopen(peerFd2, "r"); if (!peerOut) fatalp("Can't create input stream"); } // ============================================================================= void printSockInfo(char* who, sockInfo sock) { printf("%s socket is {\n\t" "sin_family = %d\n\t" "sin_addr.s_addr = %s\n\t" "sin_port = %d\n\t" "} client;\n", who, sock.sin_family, inet_ntoa(sock.sin_addr), ntohs( sock.sin_port)); }