6/26/2001 v1.80 jaf@lcsaudio.com
Jeremy Friesner/Level Control Systems
Note: To compile the server, cd to the "server" subdirectory and type 'make'. The server executable, "muscled", should be generated. You can run this server from the command line, (type "muscled help" to get info about some options) and connect to it with any MUSCLE-aware program. (The primary publicly available MUSCLE program that I'm aware of is BeShare, which can be found at http://www.bebits.com/app/1330. There is also a networked battleship game that uses MUSCLE, and a few other things floating around). The testreflectclient program in the tests directory is good for experimenting, too.
The main goal of these classes is to provide an easy way to use BMessage-style message passing across a network of heterogeneous (BeOS, Linux, Windows, etc) systems. The secondary goal is just to provide some handy data containers and other utility classes. All of this code (except the atheossupport and besupport directories) should compile under any up-to-date C++ compiler--no proprietary APIs are used.
For better documentation than this, please see the MUSCLE web site.
This code has been compiled (using gmake) and tested in the following environments:
It has no known bugs, but may have some yet-to-be-discovered ones. Use at your own risk, LCS is not responsible for any disasters, blah blah blah.
Directory contents descriptions follow:
AtheOS port of the code in the besupport folder. (See below)
This directory contains two handy functions. One converts a BMessage into a PortableMessage, and the other converts a PortableMessage back into a BMessage. These functions allow your BeOS-specific code to use BMessages internally, and only convert to PortableMessages when it's time to send them over the disk or the network. Since this code accesses the BMessage class, it will only compile on a BeOS system.
This directory also contains the MessageTransceiver class, which is a useful way to send and receive PortableMessages over a TCP socket without having to worry about blocking issues (or messing around with select()). You can just create a MessageTransceiver, and call SendOutgoingMessage() whenever you want to send something over the socket. Conversely, whenever one or more PortableMessages is received over the socket, a PORTABLE_MESSAGES_RECEIVED message is sent via your BMessenger, so your BLooper knows to process them. This class also contains convenience methods for asynchronously connecting to a remote server or accepting one or more incoming connections.
This directory contains the PortableDataIO class, which is similar to Be's BDataIO class. It also includes TCPSocketDataIO, FileDataIO, MemoryBufferIO, and NullDataIO; these are subclasses for reading/writing data to TCP sockets, disk files, in-memory arrays, and the bit-bucket, respectively.
This directory contains the AbstractMessageIOGateway interface and the PortableMessageIOGateway class, which is a "gateway" object that knows how to manage bidirectional PortableMessage-stream traffic to and from a PortableDataIO stream. It queues outgoing PortableMessages and sends them when it can, and also receives incoming PortableMessages and queues them for pickup by the user's code.
This directory contains the PortableMessage class. PortableMessage is very similar to Be's BMessage class, although it has been trimmed down a bit. Here are some relevant details:
This directory contains server code for an n-way "message crossbar server" program. This program will listen on a specified port for TCP connections, and will allow the TCP connections to "talk to each other" by exchanging PortableMessages. The ServerProcessLoop() method implements the server, while the AbstractReflectSession class is the interface for the server's side of a TCP connection. There are currently two subclasses of AbstractReflectSession included: the DumbReflectSession class just reflects all messages to all connected clients, while the StorageReflectSession class adds nice features like wildcard-based message routing, server-side data storage, and "notify-me-on-change" subscription services. (See StorageReflectConstants.h or the MUSCLE Beginner's Guide for full documentation) Other protocols can be defined by creating new subclasses of AbstractReflectSession.
This contains the Makefile and main entry point for the "muscled" server executable, and the "admin" server-tweaker utility.
This directory contains various "small things" needed to compile the rest of the code. These include byte-ordering macros, BeOS-style type codes, typedefs, and result constants, and the PortableFlattenable interface definition.
This directory contains functions for logging event messages to stdout and/or to a file. Log messages can be "raw" (works just like printf) or nicely formatted with the current time and so on.
This directory contains several silly little test programs that I used while developing the code, and a Makefile to build them with.
This directory contains many useful one-off classes and function collections, including:
PortableHashtable was originally written by Michael Olivero, and then modified by myself. PortableHashtable was inspired by the java.lang.Hashtable class, and works very similarly to that. PortableHashtable is used by the PortableMessage class, but is also useful in its own right.
NetworkUtilityFunctions.cpp is a repository for common BSD socket operations (like setting up sockets to connect or accept connections) that I'm tired of writing over and over again.
TimeUtilityFunctions.h is a repository of functions for dealing with microsecond-accurate timing issues.
The ObjectPool class is used to avoid excessive deletions and allocations of commonly used objects (such as PortableMessages or RefCountMems). It works by recycling the items for re-use, and is templated so it can be used for any type of object.
The PortableQueue class is just a little templatized double-ended queue (i.e. AddHead(), AddTail(), RemoveHead(), and RemoveTail() are O(1) operations). It can be used as a Vector, Stack, or FIFO. It's templatized for easy, type-safe reuse.
The RefCount class implements generic reference counting for C++ objects or arrays. To enable reference counting on an object, you simply create a single PortableRef for that object, and (optionally) make one or more copies of the PortableRef via the copy constructor or the equals operator. Then, when the last PortableRef object disappears, the C++ object or array is automatically deleted. It's not a garbage collector, but it beats having to keep track of all your allocations by hand...
The PortableString class is just your basic character-string class, in this case inspired by the java.lang.String class from Java. This class was originally written by Michael Olivero (mike95@mike95.com) and modified by myself. PortableString extends PortableFlattenable, so it can be serialized in a generic manner.
A string tokenizing class similar to Java's Java.util.StringTokenizer, only more efficient.
For more details, have a look at the autodocs, header files and/or the source itself.
-Jeremy