CSE 532 Spring 2008: Lab 3


Lab 3: "Interceptors and Service Reconfiguration"

Points: 25% of final grade

Submitted: by electronic submission to cse532@cec.wustl.edu

Due: by 11:59pm Sunday May 4, 2008


Purpose

The purpose of this assignment is to combine new ideas for intercepting user-triggered events and reconfiguring services, with the ideas from the previous labs of multi-threading, STL algorithms and iterators, reactive concurrency, active and passive connection establishment, and service handling.

In this assignment you will again use the basic wrapper facades for networked OO programming provided by the ACE framework, that you used in the previous labs. In this lab you will refactor and extend your lab 2 solution to provide the ability to reconfigure features of your client and server programs dynamically at run-time through a simple textual user interface. This will require you to think carefully about how your client and server programs require and provide different kinds of services, and how changes to those services can be made responsively, but in a carefully controlled manner.

In addition to providing a thorough writeup of your solution for this lab, and of how your lab designs and implementations have evolved throughout the semester, this assignment will require you to implement the following new capabilities in both your client and server programs:

  1. make your client and server programs repetitive, so that once a game has completed a new game of that same kind with that same name is started, and the clients and servers continue to run in that way until they are either terminated or reconfigured to play different games (after which the games in progress will either end naturally or be safely and consistently cancelled, at your discretion);

  2. add support for a third kind of poker game, called "hold 'em", in which each player receives 2 cards of their own (called "hole cards"), and all players share 5 common cards (called "table cards");

  3. control interfaces so that client and server services can be reconfigured dynamically, and so that changes can be made to those services safely while the client and server programs are running;

  4. a responsive textual user interface that accepts reconfiguration commands and dispatches them to the appropriate parts of your client and server programs, while the clients and servers are running;

  5. interceptors at appropriate points in your client and server programs so that reconfiguration events can be sent and detected in order to trigger consistent changes to those programs along end-to-end communication paths; and

  6. control mechanisms that when invoked by the interceptors enact the appropriate changes to the services, and which use the services' control interfaces to ensure changes are made safely while the clients and servers are running.

Optionally, you will also have the opportunity to add features for extra credit as described below, which include:

  1. the ability to support remote reconfiguration through flooding of admin commands (as noted above) so that reconfiguration can be done locally or remotely; or

  2. adding timers to the lowest level event handling layers on the server and the clients in order to vary their duty cycles according to a (re)configuration command that should specify the on-interval and off-interval of each duty cycle.


Assignment

All features that were required in lab 2 are again required in lab 3. As in lab 2, each client again can be connected to multiple servers, and each server can be connected to multiple clients. In this assignment, features such as which poker games (stud, draw, hold 'em) a client or server knows how to play, which games a client wants to play, and where clients contact game servers, will be made configurable so that they may be changed at run-time.

You will extend your lab 2 implementation to define a textual configuration command language that expresses the different configuration options for your client and server programs. You will also implement a simple textual user interface (UI) that can read those configuration commands from each client or server's standard input (for example using the cin standard input iostream), recognize the commands and their parameters, and invoke the appropriate mechanisms to ensure the commands are carried out. You will need to think about which thread(s) will manage this interface, which could be done either reactively or (probably easier) via a separate dedicated UI thread.

You will need to think about the different design dimensions of your client and server programs, along the lines discussed in Chapter 2 of the C++NPv2 textbook. This will help you decompose your design into distinct "services" that can be reconfigured more or less independently. For example, one idea may be to consider each game to be a separate service, since each instance of a game type many be configured independently of the others. Alternatively it may make more sense to have the entire clients and servers be the reconfigurable services since that is the level at which many of the reconfiguration commands are targeted. Depending on how you have designed your client and server programs, there may be other abstractions that can be configured independently, and perhaps might even replace the game instances as configurable services. Careful attention to this point may lead to some initial refactoring of your lab 2 design to make reconfiguration easier, which in the long run is likely to save more time than it costs.

For the remote command portion of the extra credit, each host (client or server) and each service you identify should be given a label, so that configuration commands can be directed to it. How you structure these labels is up to you, but one reasonable format for the labels based on the assumption that the games are configurable services would be host[:game] where "host" is the name given to the client or server on the command line, and "game" is the name given to the game on the command line.

Each of these distinct services should be given a configuration control interface similar to the one discussed in the Component Configurator lecture. You can apply these configuration control interfaces to individual objects, or (possibly by using the Facade or Extension Interface design patterns) to collections of related objects, as appropriate to isolate services from the effects of changes to other services, and to ensure changes to services are carried out consistently and safely.

You will design (or obtain from ACE or another framework) mechanisms to enact changes to services safely using those service control interfaces. In particular, some thought may be required into protocols for handshaking between configuration control mechanisms in different parts of a program or between programs, to ensure the changes are orchestrated safely, without risking deadlocks, race conditions, or other synchronization and concurrency hazards.

Finally, you will design and deploy interceptors at key points in your programs so that commands from the user and/or from other configuration mechanisms and/or interceptors are detected and dispatched appropriately (e.g., to local configuration mechanisms or to other interceptors).

To do this please perform the following tasks:

Application Features

You should make your client and server programs repetitive, so that once a game has completed a new game of that same kind with that same name is started, and the clients and servers continue to run in that way until they are terminated or reconfigured. For example, when a server finishes a game it should immediately start a new edition of the same type of game (and with the same name, but with a freshly randomized complete deck of cards) and then wait for clients to join that game; similarly, when a client finishes a game it should re-connect to the same server for the same game name and type, etc.

You should also add support for a third kind of poker game, called "hold 'em", in which each player receives 2 cards of their own (called "hole cards"), and all players share the same 5 common cards (called "table cards"), and then form hands consisting of their hole cards and whichever 3 table cards make the highest ranking hand. As in the draw and stud poker games, the player should be dealt their hole cards by the server sending them to the players and removing them from the deck. For the table cards the server should move them from the deck into a separate data structure, and then communicate what they are to each of the players in the game.

One other difference is that for each player the hand for scoring should be first chosen by picking the highest ranking combination of 3 cards from the 5 table cards with that player's hole cards. Otherwise (e.g., the content of the deck that is used, how the 5 cards chosen for each player are scored, etc.) is similar to the stud and draw poker games you have implemented in your previous labs.

Configuration Commands and Input Interpreter

Your client and server programs should recognize commands in a common text-based configuration language with which the user of a program can reconfigure any client or server on which the commands are issued (and for extra credit, can be used to reconfigure any client or server that is connected even transitively to that client or server). To do this, you should develop a common command interpreter that:
  1. reads a line of text from the standard input stream,
  2. parses the line of text until it recognizes a valid configuration command,
  3. executes the command locally if appropriate, and
  4. (extra credit only) passes the command along to any other client or server to which the command pertains.

This interpreter should run concurrently with the other activities of the client or server in which it is located. One straightforward way to achieve this is to make the interpreter an active object, with its own thread, and then add any synchronization mechanisms that are needed to avoid race conditions or other hazards when the interpreter thread interacts with other threads. Also, C++ iostreams and (especially) stringstreams can be very useful for parsing textual input (for a simple example of their use, please see the last few CSE 332 lecture slides on data and I/O).

The command language you design should include the following capabilities, though you are free to modify the syntax and/or semantics of these commands as long as (1) you document the differences thoroughly, and give examples of how each variation is to be used, in your lab writeup; and (2) all of the capabilities given here are still possible in the modified version. Note that much of the following discussion assumes that entire clients and servers are identified as distinct services, but if you choose a different service decomposition then you should update the definitions of these commands appropriately as needed.

The first set of commands is used to invoke and to configure features of the system's reconfiguration capabilities, and how the clients and servers interact with respect to them:

The second set of commands is used to configure the games played and how the clients and servers interact with respect to them:

EXTRA CREDIT: A bonus of up to 5 points (scores above 100 are possible) will be given to any team that does one or both of the following additions to their project:

  1. gives the ability to support remote reconfiguration through flooding of labeled admin and configuration commands (as noted above) so that reconfiguration can be done locally or remotely; or

  2. adds timers to the lowest level event handling layers on the server and the clients in order to vary their duty cycles according to an additional (re)configuration command that should specify the on-interval and off-interval of each duty cycle.

Teams are encouraged to try either or both of these options, and to document the designs and experiences with them in the lab writeup. Full or partial credit of as much as 5 points total will be awarded for any non-trivial efforts on these.

Service Interfaces

Each configurable service in your client and server implementations should be able to be reconfigured after it has started running. To do this safely, each service should provide a service interface which the interceptors you will add to your client and server implementations can use to initialize, terminate, suspend, or resume a service so that it can be upgraded without encountering race conditions, deadlocks, or other hazards. The following methods should be supported, per the Component Configurator pattern: The interceptors in your client and server programs (see next) should use these interfaces to ensure that configuration changes are made in a safe manner. One reasonable way to do this may be to define a consistent sequence of interactions between any interceptor and any service it reconfigures. In that case the nuances of each service's ability to be upgraded while it is running can be encapsulated entirely within its implementation of the above methods (including perhaps making some of them do nothing), which may help to simplify your interceptor implementations overall.

However, depending on how you have implemented your client and server programs, it is also possible that for one or more interceptors a different interaction sequence may be more appropriate between that interceptor and one or more of the services it configures (for example, to ensure safety or to keep the implementations of the service interface methods above from becoming overly complex). In that case you are free to vary how any interceptor interacts with the service(s) it configures, as long as you justify that decision in your lab writeup.

Interceptors and Service Repository

You should provide interceptors at appropriate places in your client and server architectures so that commands can be entered on a client or server (and for extra credit, forwarded to other clients and/or servers as appropriate), and targeted to particular services (or broadcast to all services) on a client or server, as appropriate.

One approach is to intercept configuration commands in-band, and apply special handling as needed to prevent commands from being interpreted as being application data (for example if commands are forwarded along the normal data transmission paths between clients and servers). This approach has the advantages that (1) the existing lab 2 infrastructure can be re-used significantly, and (2) commands often can be intercepted and dispatched efficiently within the handlers they affect, but the disadvantage that (3) special processing (and possibly revisions to the data transmission format) must be added to distinguish commands from non-command data.

Another approach is to intercept configuration commands entirely out-of-band in which case special purpose communication paths (e.g., built using new handlers, sockets, etc.) should be added in order to separate the command-related traffic from the data traffic. This approach has the advantage of (1) distinguishing the two kinds of traffic explicitly, but has the disadvantage that (2) new acceptors, connectors, and service handlers need to be provisioned for the command handling paths, along with the necessary concurrency and synchronization mechanisms to integrate them safely with the existing data management infrastructure from lab 2.

A third approach is to combine the out-of-band approach with the in-band approach and selectively distinguish data traffic from command traffic only at key points in the architecture where the disadvantages of doing so are less, and/or the advantages of doing so are greater. In either case, please think carefully about the trade-offs in safety, performance, and complexity, and please write up your decisions as part of your expanded README file, per the discussion of the writeup portion of the assignment below.

Testing

You should test different sequences of local (and for extra credit, remote) commands on a set of inter-connected clients and servers involved in multiple games of different types. Testing on multiple machines is strongly encouraged to catch problems that may not show up in a single machine setting.

First make sure that the basic features function correctly, and then define and execute more sophisticated scenarios to test the different sequences of potentially interacting configuration commands that cannot be tested thoroughly simply by exercising each command individually.

Writeup

In addition to documenting your design decisions and solution approach for this assignment, your README file for this lab should summarize the design challenges, patterns, and decisions you made throughout the semester, according to the criteria listed in the "what to submit" section of this assignment, below.


Resources

There are a number of resources available that can greatly ease your task in completing this assignment. This project is designed to be straightforward if you study (and use) the techniques mentioned in this section, and will be much more difficult if you do not.

Wrapper Facades

The following Wrapper Facades are provided by the ACE version installed on the CEC Linux machines at /home/cec/class/cse532/ACE_wrappers/ace/ and are highly useful for this assignment:

Service dimensions and the Service Configurator framework in ACE are discussed in detail in chapters 2 and 5 of the C++NPv2 book:

The Reactor and Acceptor/Connector pattern implementations in ACE are discussed in detail in chapters 3, 4, and 7 of the C++NPv2 book.

The concurrency and synchronization pattern implementations and wrapper facades in ACE are discussed in detail in chapters 5, 6, 9, and 10 of the C++NPv1 book:

Implementation of the Active Object and Half-Sync/Half-Async patterns and their associated wrapper facades is discussed in detail in chapter 6 of the C++NPv2 book.

STL Iterators and Algorithms

Using the STL copy (or possibly transform) algorithms to move data between files, sockets, containers, and/or output streams is a basic requirement of this assignment. Studying and using the following STL abstractions can make your task of completing this assignment much easier:

Makefile & Environment

The GNU C++ compiler (g++) is installed on the CEC Linux machines. You will need to set a few environment variables (it may be convenient to keep these in a small script file and/or simply set them in your .cshrc or .bashrc file):

setenv ACE_ROOT /home/cec/class/cse532/ACE_wrappers
setenv LD_LIBRARY_PATH ${ACE_ROOT}/ace:${LD_LIBRARY_PATH}

You will need a Makefile that links appropriately with the ACE libraries and include files. Please feel free to adapt or use the Makefile from your lab 2 solution.


What to Submit

README

When you have completed your program, please document your solution in a text file called README.

The first section of your README file should include:

  1. the number of the lab (e.g., "CSE 532 Spring 2008 Lab 3")
  2. the names and e-mail addresses of all team members
  3. an overview of how your programs are designed,
  4. the Wrapper Facades you used or extended and how they helped in your design and code,
  5. any insights and questions you encountered while completing the assignment, and
  6. if you are applying for extra credit please also describe the additional configuration capabilities your approach supports, explain your design and implementation choices for them, and give instructions for how to use and test them.

The second section of your README file should provide a detailed discussion of how your lab solutions evolved during the semester, from lab 0 through lab 3. For each of the lab assignments, please discuss

  1. what the main design challenges were,
  2. which of the design patterns we discussed in the course were applied in your lab solution,
  3. how those design patterns helped address the design challenges you faced,
  4. why you chose those design patterns instead of other alternatives (if any), and
  5. how your implementation reflected the design patterns you chose (for example, which classes in your implementation played which roles in which patterns).

The third section of your README file should provide detailed instructions for how to:

  1. unpack your files,
  2. build your programs, and
  3. run your programs.

Please indicate any and all environment variable settings, etc. you are assuming will be needed for this. I should be able to receive your e-mail, and unpack, build, and run your programs using only the instructions in your README file and the tools available on the CEC Linux machines.

Electronic Submission

Please submit by e-mail to cse532@cec.wustl.edu a single file containing:
  1. your source code files,
  2. your Makefile,
  3. any example files you think useful, and
  4. your README file.

You can use the uuencode, tar, and zip or gzip tools to do this, as in the Makefile provided for lab 2.

Please send a separate copy of your README file, with clear instructions on how your submission file was produced and how to unpack it using tools available on the CEC Linux machines.


Grading

Please treat this assignment as you would a commercial or research product that you are shipping to a large group of customers. Please take the time to test, document, and check your work to make sure all parts are shipped, and are of high quality. Grading will focus both on the quality of your solution and on the quality of the product itself, as it arrives at the cse532 account. To ensure the best possible result (and accordingly the highest possible grade), please pay attention to the following issues:

Correct Compilation and Operation

Your program must compile and run correctly on the CEC Linux machines using the Makefiles and source files you provide. Please make sure your program compiles without warnings, and you might even want to try different compilers and fix all the warnings for each. Problems with Makefiles will be handled similarly to missing files, with a 5 point deduction if you need to supply a new Makefile in order for me to build your solution on the CEC Linux machines.

Design Quality

Design decisions are largely yours to make, and as long as the design is concise, coherent, consistent, and addresses all design forces in the assignment, you will receive full credit. One key area to consider is whether each abstraction in your design does a single job, does that job completely, and collaborates appropriately with other abstractions. Minor deductions (1-3 points, but please be aware minor deductions can add up) will be made for abstractions that are unnecessarily large or have inappropriate inter-dependencies. Major deductions (5-15 points) will be made for larger problems like neglecting key design forces in the assignment.

Implementation Quality

How you implement your solution is again up to you, and I will take into account different approaches to implementation. Minor deductions will be made for things your program gets away with but are not good, like neglecting to check the return value from a system call or Wrapper Facade method (i.e., the program may have problems under special conditions) or calling exit(1) from inside a class method rather than providing a clean termination path, while major deductions will only be made for problems that produce incorrect or extremely inefficient behavior of the program. The former kinds of errors should be eliminated during your coding and code review phases, and the latter kinds of errors should be eliminated during your testing phase.

Coding Style

Different coding styles will also be accepted, as long as they are clear, readable, and consistent. Please code clearly with both the reader of the code and the user of the program in mind. Please use consistent indentation and placement of braces, and comment your code thoroughly. Use whitespace liberally - it's free and it makes it a lot easier to read your code. When grading, I will add tagged comments to the code indicating areas where I found particular issues to mention, whether or not points are deducted. Only minor deductions will be made for each style issue, except in extreme cases.

Documentation

Please make sure you provide adequate instructions on how to unpack, build, and run your program. Also, please make sure to document your solution. Minor or even major deductions will be made for inadequate explanation of how your solution does what it does, how you made key design choices, or how the user (or grader) can successfully build and run your program. Even if how you did something is obvious to you, please assume it is not obvious to the reader.

Missing Files

Missing files in the delivered software make it difficult or impossible to evaluate your solution. An automatic 5 point deduction will be applied for each missing file that is submitted later on request.

Late Submission

Labs submitted within 24 hours of the deadline will be graded with an automatic 10 point deduction. Labs submitted more than 24 hours after but within 48 hours of the deadline will be graded with an automatic 20 point deduction. Labs submitted after 48 hours from the deadline will not be graded except in extreme cases of extenuating circumstances. If you are running late completing the assignment, please let me know about the trouble as soon as possible, and please turn in as much as you can before each deadline so I can give at least some credit for the work you have done.

Grading Issues from Previous Labs

Please avoid the following practices, for which I have made comments and possibly deductions in the current semester and previous semesters, depending on the extent of the issue: Please use the following practices to improve the clarity and quality of your code and documentation: