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());
}