Ported CNAI Web Server Example
Cleansocks Example: The simple web server example from the text, ported to Cleansocks.
/* This is Comer's CNAI webserver.c example ported to use cleansocks. */ /*----------------------------------------------------------------------- * * Program: webserver * Purpose: serve hard-coded webpages to web clients * Usage: webserver <appnum> * *----------------------------------------------------------------------- */ #include <iostream> #include <sstream> #include <string> #include <stdlib.h> #include <string.h> #include <time.h> #include <cleansocks.h> #include <cleanip.h> #include <cleanbuf.h> using namespace std; using namespace cleansocks; static const int BUFFSIZE = 256; const char *SERVER_NAME = "CNAI Demo Web Server [Cleansocks port]"; /* Some long strings which form the "files" of the web server. */ static const char *ERROR_400 = "<html><head></head><body><h1>Error 400</h1>" "<p>The server couldn't understand your request.</body></html>\n"; static const char *ERROR_404 = "<html><head></head><body><h1>Error 404</h1>" "<p>Document not found.</body></html>\n"; static const char *HOME_PAGE = "<html><head></head><body><h1>Welcome to the CNAI Demo Server</h1>" "<p>Why not visit: <ul>" "<li><a href=\"http://netbook.cs.purdue.edu\">Netbook Home " "Page</a>" "<li><a href=\"http://www.comerbooks.com\">" "Comer Books Home Page<a>" "<li><a href=\"http://sandbox.mc.edu/~bennet/cs423/" "cleansocks.html\">The Cleansocks Page</a>" "</ul>" "</body></html>\n"; void handle_client(buffered_socket &conn); void send_head(buffered_socket &conn, int stat, int len); int main(int argc, char *argv[]) { if (argc != 2) { cerr << "usage: " << argv[0] << " <portnum>" << endl; exit(1); } /* Create a listening socket. */ TCPsocket listener; IPport lport = atoi(argv[1]); IPendpoint lend(IPaddress::any(), lport); bind(listener, lend); listen(listener); while(1) { /* Wait for contact from a client on specified appnum. I have extended this to print client info. */ IPendpoint rmt; sock c = accept(listener, rmt); cout << "Accepted client " << rmt << endl; /* Read and parse the request line */ buffered_socket conn(c); try { handle_client(conn); } catch(socket_error &boom) { cout << "Connection crashed while talking to " << rmt << ": " << boom.what() << endl; } close(c); } } /* * Respond to a client connection. */ void handle_client(buffered_socket &conn) { int n; /* Read the request line (first line sent), and break it into its parts. */ char buff[BUFFSIZE]; n = recvln(conn, buff, BUFFSIZE-1); buff[n] = '\0'; istringstream reqin(buff); string cmd, path, vers; reqin >> cmd >> path >> vers; /* Skip all headers - read until we get \r\n alone (blank line) or EOF. */ while((n = recvln(conn, buff, BUFFSIZE)) > 0) { if (n == 2 && buff[0] == '\r' && buff[1] == '\n') break; } /* Check for a request that we cannot understand */ if(cmd != "GET" || (vers != "HTTP/1.0" && vers != "HTTP/1.1")) { /* Send and HTTP 400 response: header, then * body, then close the connection and go back for another. */ send_head(conn, 400, strlen(ERROR_400)); send(conn, ERROR_400, strlen(ERROR_400)); return; } /* Send the requested web page or a "not found" error. * We only have two pages, so we only recognize two paths. */ if(path == "/") { /* Home page. */ send_head(conn, 200, strlen(HOME_PAGE)); send(conn, HOME_PAGE, strlen(HOME_PAGE)); } else if(path == "/time") { /* Build the time page. */ time_t tv = time(NULL); string timepage = "<html><head></head><body>" "<h1>The current date is: " + string(ctime(&tv)) + "</h1></body></html>\n"; send_head(conn, 200, timepage.length()); send(conn, timepage); } else { /* not found */ send_head(conn, 404, strlen(ERROR_404)); send(conn, ERROR_404, strlen(ERROR_404)); } } /*----------------------------------------------------------------------- * send_head - send an HTTP 1.0 header with given status and content-len *----------------------------------------------------------------------- */ void send_head(buffered_socket &conn, int stat, int len) { const char *statstr; /* Convert the status code to a string */ switch(stat) { case 200: statstr = "OK"; break; case 400: statstr = "Bad Request"; break; case 404: statstr = "Not Found"; break; default: statstr = "Unknown"; break; } /* * Send an HTTP/1.0 response header with Server, Content-Length, * and Content-Type headers. */ ostringstream hdr; hdr << "HTTP/1.0 " << stat << " " << statstr << "\r\n" << "Server: " << SERVER_NAME << "\r\n" << "Content-Length: " << len << "\r\n" << "Content-Type: text/html\r\n" << "\r\n"; send(conn, hdr.str()); }