CMSC 212
Project #5
Due 05/12/2005 8:00 PM
This project will implement at black-board engine that will allow exchanging information among bits of software. This is an example of the Observer Design pattern. Examples of applications that can use this type of system include IM servers, multi-player game engines, and distributed computing applications such as SETI@home.
You will implement a blackboard API that will relay messages to interested parties. You will also implement two users of the blackboard API to create a simple IM server.
This assignment will use TCP ports to communicate. To prevent problems, each student has a defined set of ports they may use. Your assigned ports are:
(2000 + 10 * loginID, 2000 + 10 * loginID + 9)
If your login is 10, you can use TCP ports 2100-2109. Although you will need only one port for the assignment, we provided 10 in case of problems with any one of them.
boardHandle connectBlackboard(char *id)
Connect to a blackboard. The id is the name of a blackboard user.
int registerMessageHandler(boardHandle, char *eventType, eventHandlerFunc)
Register a message handler. Whenever a message of type eventType is sent, function passed in eventHanderlFunc is called. If a NULL value is passed for eventHandlerFunc, the existing handler for that message type should be removed.
int registerNewUserHandler(boardHandle, newUserHandlerFunc)
Register a function to be called whenever a new user connects or leaves the system. If a NULL value is passed for newUserHandlerFunc, the existing new user handler for that boardHandle should be removed.
int sendMessage(boardHandle, char *eventType, int lineCount, char *data[])
Send a message to all users of the blackboard (except the sender of the message) who currently have a message handler for a message type eventType. If there are no such users, the message is simply discarded. The message consists of lineCount lines sent in an array of character pointers in data.
int leaveBlackboard(boardHandle)
User with “id” is leaving the system. All registered event handlers for that user should be deleted.
int registerFileEventHandler(int fd, eventHandlerFunc)
Register a function, eventHandlerFunc, to be called when ever there is data to be read from the file descriptor fd. If a NULL value is passed for eventHandlerFunc, the existing handler for that file descriptor should be removed.
void blackboardMainLoop()
Main event loop of the system. Wait in a loop for new data to arrive on one of the file descriptors that has an event handler defined. This loop should never return unless there are no file descriptor handles registered.
Unless otherwise indicated, all API routines with an integer return value should return 0 for success, and –1 for any sort of failure or error case.
The file blackboard.h (which you may not change) contains the definitions for the following function pointer types for the various callback functions in the API.
typedef void (newUserHandler*)(char *id, int arriving);
typedef void (eventHandlerFunc*)(boardHandle board, char *id, char *event,
int lineCount, char *data[]);
typedef void (*fdEventHandlerFunc)(int fd);
As part of this assignment you will build a chat system that uses your blackboard API. The way the chat system works is that each user will send messages to the blackboard system. The blackboard system will distribute these messages to other users. You will write two chat components (besides the main routine): console and proxy. You may use any message type you want for the communication in your chat application (we used “im”).
The console chat user will read messages from standard input and print any messages it receives to standard output. Since this is an event driven program, you will need to register a read event handler for the file descriptor associated with standard input (0). This read event handler will then call fgets to get a line of input and send it to the blackboard server. Your client should also have an event handler for users arrival/departure events and print a message of the form “User <user name> [joined|left] the chat”. On end of file to standard input (control-D), the chat system should exit.
The proxy user allows remote users to connect to your blackboard system (sort of like a very simple IM system). To do this, your proxy will wait for new TCP connections on a socket at a port number which is passed in as a command line argument to the blackboard system.
The proxy will define a read event handler that is bound to the supplied port. When a new connection arrives, that handler function will get called. This handler function will use the accept system call to get a network connection to the new user. It will create a blackboard handle for the remote user. It will then create a new file descriptor event handler that calls a function remoteUserHandler when new data arrives for that user. It should also register a message handler for this connection. When the new the message handler is called, it should send the message to the remote connection (via the write system call). When the remoteUserHandler is called (indicating data to be read from the remote user), the handler should use the read system call to get the data from the network and pass it to the blackboard system via a sendMessage call.
To test your proxy, you can use the Unix command telnet to connect to your IM server. Use the command “telnet localhost <port>” where port is the port number you supplied when starting your blackboard server.
A sample binary version of the blackboard program is installed on the class Linux machines as blackboardSample. You can run it and see how the system is supposed to work.
We have also supplied a user for the blackboard system. This user is a robot chatter that will read other peoples messages and attempt to reply in a way that appears that it is another person. This client is called Eliza[1] and is supplied in the file eliza.o. As far as you are concerned, this user is simply a plug-in and all you need to do to use it is to link the file eliza.o into your blackboard program and call the function initEliza() before blackboardMainLoop().
Your project should produce one UNIX executable file (blackboard) which contains the blackboard routines (blackboard.c), the console client (main.c), the proxy client (proxy.c). We will supply a third client (eliza.o) which uses the blackboard API, eliza.o should also be linked into the blackboard executable. Your blackboard program should take one command line argument, port, which is the port the proxy should listen on for network connections.
The following picture shows the structure of the project.
blackboard

[1] Eliza was the name of an early program that attempted to respond to commands in a way that mimicked human intelligence.