Go to the first, previous, next, last section, table of contents.


Class interface

This chapter documents the interface of the various MUSES classes, and the relationships among them.

All MUSES classes are part of the muses namespace; their names should be fully qualified (as in muses::Server), imported as needed in the global namespace (via `using muses::CLASSNAME;'), or imported as a whole (using namespace muses;).

Concrete classes

These classes are common to all the possible MUSES servers. Among them, only the Server class needs to be instantiated by the end user. The framework will create and destroy ServerPort and Connection objects when needed; such objects can be accessed via the Server. Moreover, the current Connection is passed as a parameter to user-defined event handlers.

Server

A Server represents the entire MUSES server. It can perform a few high-level operations, the most important of which are:

The Server class provides other, less frequently needed, methods:

ServerPort

This class represents a port on which the server is listening; it manages all the connections currently open on that port.

Users should seldom be interested in this class; the main reasons to use it directly are reading the list of active connections, and replacing the current ConnectHandler.

ServerPort objects are created and destroyed by their Server; they can be accessed via the Server or via a Connection they accepted.

ServerPort provides the following methods:

Connection

A Connection is a client's connection to a given ServerPort. The list of connections can be obtained via a ServerPort; most handlers are passed the current Connection when invoked.

Its most important features:

Some other, possibly less useful methods:

Base classes

MUSES provides only a framework for internet servers, and thus only implements the features that are common to most kinds of servers. The specific aspects that make a server different from another have to be implemented via event handlers. MUSES requires several different kinds of handlers, corresponding to the abstract base classes described below.

MUSES also provides a standard way of attaching custom data to a Connection:

Finally, it is possible to preprocess the contents of the output buffer, right before sending them to the client, in a way that is transparent to the application:

ConnectHandler

ConnectHandler objects tell a ServerPort what to do when a client tries to connect. They are expected to set up appropriate handlers on the newly-made Connection, and possibly to greet the client.

The entry point to a ConnectHandler is

  void operator () (muses::Connection& newConnection)

ReceiveHandler

A Connection's ReceiveHandler is invoked whenever some new data reaches the Connection's input buffer. The handler is expected to return the number of bytes that have been read and that can be dropped from the buffer.

The entry point to a ReceiveHandler is given as arguments the current connection and the number of bytes that are waiting to be read:

  unsigned int operator () (muses::Connection& connection,
                            unsigned int len)

The default (null) handler throws away everything it receives without doing anything else.

If the input buffer ever becomes full, and the ReceiveHandler does not manage to handle some data, the current connection is automatically dropped.

LineHandler

The ready-made handler RH_LineSplitter splits incoming data into lines and parses each line separately. This parsing is done by calling a LineHandler.

The entry point to a LineHandler is as usual operator():

  void operator () (muses::Connection& connection, std::string& line)

DisconnectHandler

This kind of handler tells a Connection what to do when link is closed. Usually, some kind of cleanup will be needed.

The entry point is as usual operator():

  void operator () (muses::Connection& deadConnection)

When the handler is invoked, the Connection is already closed; it is safe to read whatever remains in its buffer, but of course it is pointless to send it further data.

TimeoutHandler

This handler is invoked when the network remains idle long enough. The handler is passed the current Server:

  void operator () (Server& server)

ConnectionData

Any kind of data can be attached to a MUSES connection. This is done by storing such data in a subclass of ConnectionData, and by linking it to a Connection via Connection::setData().

The attached data can be retrieved as follows:

  MyData *data = dynamic_cast<MyData*>(myConnection.data());

data will contain a pointer to the stored data, or zero if no data of the appropriate type is available.

The ConnectionData class does not contain any data member, and it does not define any method apart from a constructor and a virtual destructor. Therefore, it is an excellent candidate as a mix-in base class. A concrete data class can inherit from both ConnectionData and any pre-existing class, without incurring in most of the disadvantages of multiple inheritance.

SendFilter

MUSES stores the server output in a buffer before sending it to its clients. Just before flushing the buffer, MUSES can perform any kind of operation upon its contents, in a way that is transparent to the application. This is done by using a SendFilter. This feature can be used to implement communication protocols, to perform on-the-fly stream encryption...

A SendFilter must be capable of performing three operations:

  SendFilter *clone() const;
  unsigned int length(const char *buf, unsigned int len);
  unsigned int filter(const char *buf, unsigned int len, char *dest);

Connection::setSendFilter(SendFilter*) attaches a SendFilter to a Connection. This can be done more easily via <<. The newly specified filter will work until replaced by a new one. You may safely deallocate a SendFilter after passing it to a Connection, since the Connection will make its own copy. For the same reason, it may be unwise to store plenty of data into a SendFilter.

If you want to disable output translation, just use the globally predefined SendFilter raw:

  myConnection << muses::raw << "This text will not be filtered."
               << endl;

Ready-made handlers

Beside providing a framework for internet servers, MUSES contains some ready-made event handlers to be used in common situations. More ready-made handlers might become available in the future.

RH_LineSplitter

This ReceiveHandler splits the incoming data into lines, and passes each line to a LineHandler to be parsed.

The active LineHandler can be determined in the constructor, and can be changed at any time via setLineHandler(handler*).

RH_Telnet

This ReceiveHandler implements a very minimal version of the telnet protocol, and forwards filtered data to another ReceiveHandler.

RH_Telnet only unescapes incoming IAC characters, refuses all options (answering DONT to WILL and WONT to DO), and ignores other commands. Derived classes may override the handleIAC() method and implement a more detailed version of the protocol.

The sub-handler to which filtered data is passed can be chosen when creating the RH_Telnet object, and can be changed at any time via setReceiveHandler(handler*). A null handler will throw away data without doing anything.

SF_Telnet

This SendFilter converts outgoing IAC characters into IAC IAC pairs. A telnet-compliant client will convert the pair back to a single IAC before doing anything else with it.

Since this SendFilter is likely to be used quite frequently, MUSES provides a global instance of it, called sf_telnet. Just pass it to a Connection in order to enable outbound telnet conversion:

  myConnection << sf_telnet;

If you want to send a raw IAC character (perhaps because you're sending a telnet command!), you should disable outbound filtering and then re-enable it:

  myConnection << raw << IAC << my_usual_telnet_filter;

To make things easier, MUSES provides a iac global that does the same:

  myConnection << iac;

Exceptions

In case some critical error happens, MUSES throws exceptions for the caller to catch. This is done when the error would not allow the server to start or to continue working, or when a serious bug is detected. Recoverable error conditions are handled more gently, usually by disconnecting the user that is having trouble.

All MUSES exceptions derive from MusesException, which is in turn a std::exception. Therefore, their what() method returns an error std::string describing the problem. Apart from this, some MUSES exceptions provide further troubleshooting data.


Go to the first, previous, next, last section, table of contents.