Applying Patterns and Framework Components to Develop a Web Server

The purpose of this assignment is to deepen your understanding of reactive I/O, OO event demultiplexing, and Active Objects in the context of the ACE C++ toolkit. In this assignment, we will write a simple WWW server. In brackets are some hints about what kinds of ACE classes you might want to look up to do these (see ACE HTML manual pages and ACE tutorial reference for additional details).

In addition to the ACE C++ socket wrappers, the components that you must use for this assignment are the ACE ACE_Reactor and ACE_Acceptor.


WWW Server

The concurrent multi-threaded server program should do the following activities:

  1. Create an Internet domain ``passive-mode'' stream socket on a port number specified on the command line [ACE_Acceptor,ACE_Svc_Handler,ACE_SOCK_Acceptor] and wait in the main thread for connections to arrive from clients.

  2. When a client request arrives, the handle_input method of the ACE_Acceptor will automatically accept the connection and call the open method of HTTP_Handler, which is a subclass of ACE_Svc_Handler that you use defined. The open method is a hook that you fill in to activate your service handler once the connection has been established.

    There are a number of ways to implement the open hook function. One way is to turn the newly connected service handler into an Active Object (using the activate method inherited from ACE_Task), when then carries out the client request in the service handler's svc hook, which you must write. Another way is to use reactive I/O via the ACE_Reactor. I want you to use the hybrid scheme that we discussed in class, whereby there's a Reactor on the bottom and an Active Object containing a thread pool on the top. See the class notes for more details on this.

  3. When a client request arrives, the ACE_Reactor will call back to the handle_input method of the HTTP_Handler, which will read the HTTP GET request, such as:
    
    GET /index.html HTTP/1.0\n\n
    
    Make sure that your HTTP_Handler is intelligent about not getting hung indefinitely on blocking send and recv calls. I recommend using the ACE_SOCK_Stream timed I/O calls.

  4. One the request is completely received, encapsulate it into an ACE_Message_Block and put it to the ACE_Task, where it will be stored in the ACE_Message_Queue and subsequently removed and processed by a thread in the thread pool. Once it's in a thread, open the file in your local .www-docs [ACE_FILE_Connector,ACE_OS::access(2)], send the contents back to the client, and close the socket. For this assignment, assume that the client is requesting a file, rather than a directory listing.

  5. The server should not exit unless you explicitly kill it via a signal (e.g., SIGINT). You should add a signal handler (using either the ACE_Reactor signal interface or the ACE_Sig_Action interface) that performs any termination code necessary to gracefully shutdown the server upon receipt of a signal. It is hard to come up with a completely portable scheme for handling signals and shutting down tasks in multi-threaded programs. For this assignment, you can simply exit the server, which will close down all the open sockets. We'll cover more portable and robust mechanisms for closing down the server later in the course.


Comments

I strongly encourage you to produce reusable C++ components based on the code you write. We will reuse these components throughout the course.


References