Multi User Server Client Linkage Environment v4.24

Open Source Software by Meyer Sound Laboratories Inc

Written by Jeremy Friesner, Last Updated 4/28/2008


Download the latest MUSCLE source and documentation (v4.24)

Subscribe to the MUSCLE developer's mailing list

Read the Beginner's Guide to MUSCLE

Read the Guide to making a custom MUSCLE server

Demonstration of how to add multithreading to a custom MUSCLE server (v1.03)

Read the README file

Read the BeShare and MUSCLE BeNews article

MUSCLE is licensed under the BSD Open Source License

Study the MUSCLE API autodocs

Study the Java Client API Javadocs

Download previous versions of MUSCLE


What is MUSCLE?

MUSCLE is a robust, somewhat scalable, cross-platform client-server messaging system for dynamic distributed applications that runs under any POSIX-compliant operating system. MUSCLE has been developed, used, and refined as the networking component of BeShare, CueStation and various other audio control applications at Meyer Sound Laboratories for over six years. With MUSCLE, you can:


MUSCLE version history (recent releases only; for the full history see the HISTORY.txt file in the muscle archive)

key:  - new feature
      * bug fixed
      o other

4.24 Released 4/28/2008 
  - If MUSCLE_USE_LIBRT and _POSIX_MONOTONIC_CLOCK are defined,
    GetRunTime64() and Snooze64() will now use librt's high-resolution
    functions (clock_gettime() and clock_nanosleep()) instead of
    the older vanilla POSIX functions.  This can provides higher 
    resolution timing on platforms that support librt.
  - Added a new ExecuteSynchronousMessaging() virtual method
    to the AbstractMessageIOGateway class, and some associated
    hook/callback methods.  This method lets you easily do 
    synchronous/RPC-style "function calls" across the gateway's
    socket, passing in one or more Message objects as the 
   "arguments", and receiving one or more Messages as "results".
  - MessageIOGateway now overrides ExecuteSynchronousMessaging(),
    IsStillWaitingForSynchronizedReply(), and
    SynchronousMessageReceivedFromGateway() so that when you
    call ExecuteSynchronousMessaging() on it you will get
    proper RPC function-call semantics.
  - Added an IsReadyToAcceptSessions() virtual method to the
    AbstractReflectSessionFactory class.  Subclasses can override
    this method to return false if they don't want to accept
    any more connections for a while.
  - Added an IsConnected() method to the AbstractReflectSession
    class, to make it easier to check if a given session is
    currently connected to anything or not.
  - Added an XorDataIO class to the dataio folder.
    XorDataIO XOR's all the data going through it, before
    forwarding the method call to its held child DataIO object.
  - Added a MutexGuard class that you can put on the stack
    to automatically lock/unlock a Mutex via its ctor/dtor.
  - Added versions of ReadZipFile() and WriteZipFile() that
    take a DataIO reference instead of a file name.  That way
    you can read zip files over the network, through custom
    filters, and so on, if you want to.
    zlib/ZipFileUtilityFunctions.{cpp,h}.
  - ReadZipFile() now has an optional second argument called
    (loadData).  Setting it false will cause ReadZipFile to
    only read in the file names and uncompressed file lengths,
    but not actually read or uncompress the file data.  This 
    is useful if you just want to quickly check the zip file's
    contents without actually unpacking everything.
  - Updated testzip.cpp to accept an optional "namesonly"
    command line argument, which will set (loadData) to 
    false in its ReadZipFile() call, as described above.
  - Added a GetNetworkInterfaceAddresses() function, as an
    easier-to-use alternative to GetNetworkInterfaceInfos().
  o Made AbstractReflectSession::IsConnectingAsync() public.
  o Moved Snooze64() from NetworkUtilityFunctions.cpp to
    SetupSystem.cpp, and moved its function declaration from
    NetworkUtilityFunctions.h to TimeUtilityFunctions.h.
  * Joel Lucsy reported a bug in FlattenToDataIO() that would cause
    the last four bytes of the flattened buffer not to be written
    to the DataIO object.  Fixed.
  * Updated zlib's included VC++ project files to reference zconf.h
    in its new location (zlib/win32/zconf.h) so that they now work
    again.

4.23 Released 3/26/2008
  - Added an UnparseArgs() function to MiscUtilityFunctions.{cpp,h}.
    This function takes a parsed Message and turns it back into a String.
  - Added an InsertItemsAt() method to the Queue class.
  - Added an (includeLocalhost) boolean argument to GetNetworkInterfaceInfos().
  - Made ServerComponent::SetOwner() and ServerComponent::GetOwner()
    public, as it is necessary for classes other than ReflectServer
    to access that value in order to properly support the facade
    pattern within ReflectSessionFactory objects.
  - Added a ProxySessionFactory class to support facade-style
    ReflectSessionFactories better.
  - Added an optional ITraversalPruner argument to both
    StorageReflectSession::SaveNodeTreeToMessage() and
    StorageReflectSession::RestoreNodeTreeFromMessage().  This
    argument lets the caller specify a callback argument that
    can direct the traversal based on custom logic, if necessary.
  o Replaced StorageReflectSession::CloneDataNodeSubtree()'s rather clunky
    MessageReplaceFunc and void-pointer filtering mechanism with the nicer
    and more powerful ITraversalPruner filtering mechanism.
  * Fixed a bug in FilterSessionFactory and SharedFilterSessionFactory
    where an assertion failure would occur if the "slave" factory attempted
    to call GetSessions(), etc.
  * SharedFilterSessionFactory's IP-address checking was broken.  Fixed.
  * AbstractReflectSession::GetPort() was broken and would always
    return 0.  Fixed.

v4.22 Release 3/4/2008
  - Added an IsDaemonProcess() function that returns true iff
    the current process was created via SpawnDaemonProcess()
    or BecomeDaemonProcess().
  - Added a AssembleBatchMessage() convenience function to
    MiscUtilityFunctions.{cpp,h}.  It's useful for creating a
    PR_COMMAND_BATCH Message from zero or more other Messages.
  - The NestCount class will now cause an assertion failure
    if Decrement() is called when it is already at zero...
    that should never happen in correct code.
  - Added an optional (numColumns) argument to the
    PrintHexBytes() utility function.
  - Added a templatized bit-chord class, support/BitChord.h.
  - Added ReadData() and WriteData() functions to
    NetworkUtilityFunctions.{cpp,h}.  These are the same
    as SendData() and ReceiveData(), except that they call
    read() and write() instead of send() and recv().
  - Replaced the PrintHexBytes() implementation with the
    superior one from hexterm.cpp.
  - Added a GetWithDefault() convenience method to the
    Hashtable class.
  o Moved the Win32 version of zconf.h from zlib/zlib to
    zlib/zlib/Win32, so that it wouldn't show up in SVN
    as modified whenever the configure script modified it.
  o Changed the default value of MUSCLE_POOL_SLAB_SIZE to
    4 kilobytes, to reduce memory overhead somewhat.  This
    value coincides nicely with the most common memory page size.
  * The POSIX implementation of RS232DataIO was broken, because
    it was trying to use SendData() and ReceiveData() on the
    serial port's (non-sock) fd.  Changed it to call ReadData()
    and WriteData() instead.
  * Rewrote the Unix implementation of ChildProcessDataIO to
    call forkpty() instead of doing everything by hand.  This
    makes the implementation much simpler and more reliable,
    although of course it will only work on systems that have
    forkpty() available.
  * ChildProcessDataIO now closes any forked file handles in the
    child process before calling exec().
  * Made the PacketTunnelIOGateway parsing more flexible;
    duplicate packets no longer break a logical stream.
  * Removed several files from the zlib/zlib folder that are
    meant to be generated by the configure script.

v4.21 Released 1/22/2008
  - Optimized Hashtable::GetOrPut(), CopyToTable(), MoveToTable(),
    Put(), and Remove() to be more efficient.
  o Updated the muscle.dox DOxygen file to reflect changes to
    newer versions of DOxygen
  * Hashtable::Put() and Hashtable::Remove() now do the right
    thing if they are passed (*this) as an argument.
  * Fixed a nasty bug in the ObjectPool destructor that would
    cause it to go into an infinite loop, calling delete on
    the same array over and over again.
  * Filled in and fixed up the DOxygen comments to the point where
    DOxygen no longer gives any warnings when generating the autodocs.
  o Updated all copyright notice headers to read 2000-2008 Meyer Sound.

v4.20 Released 12/31/2007
  - Added an optional set of multicast networking API calls
    to util/NetworkUtilityFunctions.h.  Define the constant
    MUSCLE_ENABLE_MULTICAST_API to make them available.
  - hexterm will now automatically use multicast UDP if you
    specify a multicast UDP address as an argument.  For example,
    ./hexterm udp=239.255.1.2:4001
  - Added SetSourceExclusionID() and GetSourceExclusionID()
    methods to the PacketTunnelIOGateway class, to enable more
    efficient filtering of looped-back broadcast/multicast packets
    that you sent out and don't want to see back again.
  - Added a ParseHexBytes() function to MiscUtilityFunctions.{cpp,h}
  - Under Linux, HandleStandardDaemonArgs() now takes a new argument
    "debugcrashes" which will cause a signal handler to be installed
    that will catch SIGSEGV, SIGBUS, SIGILL, SIGABRT, and SIGFPE,
    and print a stack trace to stdout before exiting.
  - Added RemoveFirst() and RemoveLast() convenience methods
    to the Hashtable class (handy when using the Hashtable as
    a keyed FIFO or LRU)
    o Moved the PrintHexBytes() function into system/SetupSystem.cpp
    so that you don't have to link in MiscUtilityFunctions.cpp
    just to use it.
  * Tweaked FinalizeAsyncConnect() to work properly under BeOS.
  * Improved the BeOS/BONE detection -- Makefile support no
    longer required.

v4.11 Released 12/11/2007
  - GetHumanReadableTimeString() and ParseHumanReadableTimeString()
    now handle the uint64 value MUSCLE_TIME_NEVER as a special case,
    by translating it into the string "(never)" (and back).
  - Added a CalculateChecksumForUint64(), CalculateChecksumForFloat(),
    and CalculateChecksumForDouble() convenience functions to 
    MuscleSupport.h
  - Added a FindFirstMatchingNode() method to the DataNode class,
    which can be used to efficiently look up a descendant node
    based on a relative or absolute path, with or without wildcard
    matching characters.
  - Added a GetRootNode() convenience method to the DataNode class
    which returns the root node of the DataNode tree.
  - Added SetAllowMiscIncomingData() and GetAllowMiscIncomingData()
    methods to the PacketTunnelIOGateway class, so that a UDP socket
    controlled by a PacketTunnelIOGateway can optional receive
    individual (non-packetized) arbitrary UDP packets as well as
    the packetized kind.  This mode is disabled by default.
  - Added a Normalize() method to the Queue class that can be used
    to ensure that the Queue's contents are layed out contiguously
    in memory (like a C array).
  - Added a AddNewDormantConnectSession() method to the ReflectServer
    and ServerComponent classes.  This method is the same as 
    AddNewConnectSession() except that the added session will not
    start a TCP connection immediately; instead it will hang out
    and wait for you to call Reconnect() on it.
  - Added a PrintHexBytes() convenience/debugging function to
    MiscUtilityFunctions.h
  o Removed the (countFieldOrder) argument from the 
    Message::CalculateChecksum() method.
  o Changed instances of ((uint32)-1) literals to the more proper 
    MUSCLE_NO_LIMIT constant in a number of places.
  o Rewrote StorageReflectSession::GetDataNode() as a simple
    inline call-through to FindFirstMatchingNode(), which means
    that GetDataNode() now supports wildcard matching.
  o GetHumanReadableTimeValues() now returns B_ERROR if you pass
    it MUSCLE_TIME_NEVER as a time value (since there is no good
    numeric way to represent infinity).
  o DataNode::PrintToStream() and Message::PrintToStream()
    no longer print this-pointer values in their debug output,
    because doing so makes it harder to diff state dumps
    from different processes.
  o AbstractReflectSession::Reconnect() and SetAutoReconnectDelay()
    can now be used in conjunction with sessions that were not
    added with AddNewConnectSession() also.  In this context, they
    will "reconnect" the session by destroying its gateway and
    DataIO objects and creating new ones by calling 
    CreateDefaultSocket() and CreateDataIO().
  * system/AcceptSocketsThread.h was missing a necessary #include
    line.  Thanks to Mika Lindqvist for reporting this.
  * Fixed a bug in DataNode::InsertOrderedChild() that could cause
    the inserted child's node name not to be unique in some
    circumstances.
  * DataNode::PutChild() now takes a (const DataNodeRef &) instead
    of a (DataNodeRef &).
  * Removed the index-order multiplication from most implementations
    of CalculateChecksum(), since including an index-multiplier
    in the checksum makes it inefficient to update a running
    checksum tally when inserting or removing items in the list.
  * The Thread class now closes the internal thread's side of
    the inter-thread socket connection when the internal thread
    hook function exits.  That way the main thread can be notified
    that the child thread has gone away (the main thread's socket
    will select() ready-for-read because of the socket close)

v4.10 Released 10/30/2007
  - Added Bryan Varner's MicroMUSCLE port to the archive, in
    the new java_j2me folder.  MicroMUSCLE is a fork of the
    MUSCLE Java code that is compatible with the J2ME edition
    of Java being used on modern cell phones, etc.  Unlike
    the standard MUSCLE Java API, this version doesn't require
    Java 1.4.x APIs to be supported.
  - Added a GetNumberOfProcessors() function to the SystemInfo.h
    API.  You can call this to find out how many CPU cores the
    computer you are running on has.
  - Made LockLog() and UnlockLog() part of the public MUSCLE
    syslog API, in case you want to use the log mutex in your
    own critical section.
  - Added a CalculateChecksum() utility function to MuscleSupport.h
  - Added CalculateChecksum() functions to the String, ByteBuffer,
    Point, Rect, Message, and DataNode classes.  These methods 
    compute a quick checksum on the object's contents which can 
    then be used for sanity-checking later on.
  - Added a PrintToStream() method to the DataNode class for
    quick recursive dumping of database subtrees to stdout.
  - Message::PrintToStream() and Message::ToString() now include 
    the checksum value of the Message.
  - Added IsInBatch() and IsOutermost() methods to the NestCount
    class, for convenience and code clarity.  (Before they were 
    only present in the NestCountGuard class)
  - Added a KillChildProcess() method to the ChildProcessDataIO
    class, for times when you need the child process dead right
    away but you want to keep the socket to it open (so that it
    will error out as if the child process died of its own accord).
  - Added IsDescendantOf() and IsAncestorOf() convenience methods
    to the DataNode class. 
  - Added a StringCompareFunc() override to String.h that takes
    (const String *)'s as arguments.  Useful when you want to
    save space in a Hashtable of string-keyed, ref-counted 
    objects, by changing the key-type to a pointer to a string
    that is held in the referenced value-objects.
  - Added a Message::FindString() method override that sets a
    pointer-to-a-String, so that you can access the underlying
    String object without having to copy it.
  - Added a ServerComponent::GetSession() override that takes
    a uint32 for the session ID argument.
  - Added convenience versions of StringMatcher::Match()
    and HasRegexTokens() that take a String argument instead
    of a (const char *).
  - Added a GetEmptyMessageRef() convenience function to
    Message.h.  It's like GetEmptyMessage() except it returns
    a (const MessageRef &) instead of a (const Message &).
  - The StdinDataIO class now works as expected under Windows.
    In particular, it implements some backstage trickery so that
    you can use its GetSelectSocket() return value in select() 
    even though Windows doesn't support doing that.
  o Removed GetBlankMessage() from the StorageReflectSession
    API.  Use GetEmptyMessageRef() instead.
  o DataNode::GetData() now returns a (const MessageRef &)
    instead of a MessageRef.
  o The GetSessions() method now returns a Hashtable instead
    of a HashtableIterator.
  o The GetNumSessions() method has been removed; use
    GetSessions().GetNumItems() instead.
  o The GetFactories() method now returns a Hashtable instead
    of a HashtableIterator.
  o The GetNumFactories() method has been removed; use
    GetFactories().GetNumItems() instead.
  o Tweaked some of the code to avoid new warnings in gcc 4.1.x
  o The SetDataNode(), FindMatchingSessions(), CloneDataNodeSubtree(),
    NotifySubscribersThatIndexNodeChanged(), NodeIndexChanged(),
    GetNewDataNode(), and JettisonOutgoingSubtrees() methods
    in the StorageReflectSession class not take String arguments
    instead of (const char *)
  o The InsertOrderedChild(), ReorderChild(), HasChild(),
    GetChild(), and RemoveChild() in the DataNode class now all 
    take String arguments instead of (const char *).
  o DataNode::GetPathClause() now returns a (const String *)
    instead of a (const char *).
  o FilterSessionFactory Put*Pattern() and Remove*Pattern()
    methods now take (const String &) arguments instead of
    (const char *).
  o The StdinDataIO class no longer derives from the
    FileDescriptorDataIO class.  This way it is possible to
    use StdinDataIO under Windows (which doesn't support
    file descriptors).
  o Moved the StdinDataIO code into its own separate StdinDataIO.cpp
    file, to better hide the ugly Windows implementation. 
  * Fixed a VC++ compatibility issue in ObjectPool.h.  Thanks to
    Mika Lindqvist for reporting this problem.
  * Fixed a bug in AcceptSocketsThread.cpp.  Thanks to Mika
    Lindqvist for reporting this problem also.
  * Fixed a HANDLE leak in the Windows implementation of the
    RS232DataIO and ChildProcessDataIO classes.

v4.00 Release 10/03/2007
  *** WARNING - THIS RELEASE RATIONALIZES SEVERAL APIS AND THUS ***
  *** BREAKS SOURCE COMPATIBILITY WITH MOST OLD CODE.  DONT     ***
  *** UPGRADE TO THIS RELEASE UNLESS YOU ARE WILLING TO UPDATE  ***
  *** YOUR CODEBASE TO MATCH.                                   ***
  - Added a SanitySetupSystem class to the CompleteSetupSystem
    object.  SanitySetupSystem just does some very quick tests
    on the typedef sizes (int16, int32, etc) and endian-ness
    of the compiled code to make sure that the code's build
    settings are compatible with the run-time environment.
    If any of the tests fail, it prints out a stern error
    message and aborts the program.
  - Added convenience methods for AddFlat(), PrependFlat(), 
    FindFlat(), and ReplaceFlat() to the Message class that 
    take a ByteBufferRef as an argument.  That way you can
    deal with Messages and ByteBufferRefs without always
    having to look up how to cast a ByteBufferRef to a
    FlatCountableRef and back.
  - Added HasChars() and IsEmpty() convenience methods
    to the String class, for consistency with the other
    container classes.
  - Rewrote the ObjectPool class to do its object allocations
    in 8 kilobyte "slabs" rather than one at a time.
    This cuts down on the number of calls to new/delete
    by an order of magnitude.
  - Added a -DMUSCLE_POOL_SLAB_SIZE build option in case
    you want the ObjectPools to use a different slab size.
    This value is specified in bytes.
  - Added an ExitWithoutCleanup() function to 
    MiscUtilityFunctions.{cpp,h}, which is equivalent to
    _exit().  This wrapper function exists because I
    suspect _exit() may not be entirely portable.
  - Added a "testpool" program to the tests folder to
    measure the relative efficiency of various 
    object-allocation techniques.
  - AbstractReflectSession::GetSessionIDString() now returns 
    a (const String &) instead of a (const char *).
  - Added a GetSessionID() accessor to AbstractReflectSession.
  - Added a CreateDefaultSocket() method to the 
    AbstractReflectSession class.  This method is called
    when AddNewSession() is passed a null SocketRef, and 
    if implemented to return a non-NULL SocketRef, can be
    used to provide a default socket for the session.
  o Renamed the SocketHolderRef class to Socket.
  o Added the a SocketRef class (which subclasses Ref)
  o All MUSCLE functions that previously dealt with sockets
    as integer file descriptors now use the new SocketRef 
    type instead.  This way there is no chance of leaking or 
    double-freeing allocated sockets.
  o Removed the CloseSocket() function from the API, since
    it is no longer necessary.
  * Changed the static casts in StorageReflectSession.cpp
    to dynamic_cast<>, so that ReflectServers holding some 
    sessions derived from StorageReflectSession and some 
    derived directly from AbstractReflectSession will now 
    work without crashing.
  o Removed GetDataIORef() and GetGatewayRef(), and changed
    GetDataIO() and GetGateway() to return references to Ref 
    objects instead of pointers to objects. 
  o AbstractReflectSession::CreateDataIO() now takes a 
    (const SocketRef &) argument instead of an int, and now 
    returns a DataIORef instead of a (DataIO *)
  o AbstractReflectSession::CreateGateway() now returns an 
    AbstractMessageIOGatewayRef instead of a 
    (AbstractMessageIOGateway *)
  o ReflectSessionFactory::CreateSession() now returns an 
    AbstractReflectSessionRef instead of a (AbstractReflectSession *)
  o StorageReflectSession::GetNewDataNode() now returns a
    DataNodeRef instead of a (DataNode *).  This way any
    chance of a memory leak is avoided.
  o StorageReflectSession::ReleaseDataNode() has been
    removed since it is no longer necessary.
  o RefCountable's copy constructor no longer copies the
    _manager pointer, since items allocated in one ObjectPool
    can no longer be freed by a different ObjectPool.
  o MessageTransceiverThread::CreateSupervisorSession() now
    returns a ThreadSupervisorSessionRef instead of a 
    (ThreadSupervisorSession *)
  o MessageTransceiverThread::CreateDefaultWorkerSession()
    now returns a ThreadWorkerSessionRef instead of a
    (AbstractReflectSession *)
  o MessageTransceiverThread::CreateDefaultSessionFactory()
    now returns a ThreadWorkerSessionFactoryRef() instead of
    a (ReflectSessionFactory *).
  o ThreadWorkerSessionFactory::CreateThreadWorkerSession()
    now returns a ThreadWorkerSessionRef instead of a
    (AbstractReflectSessionRef *).
  o The MessageTransceiverThread::AddNew*Session() family
    of methods now take a (const ThreadWorkerSessionRef &) 
    argument instead of (const AbstractReflectSessionRef &).
  o The MessageTransceiverThread::PutAcceptFactory() family
    of methods now take a ThreadWorkerSessionFactoryRef
    argument instead of a ReflectSessionFactory.
  o MessageTransceiverThread::CreateReflectServer() now 
    returns a ReflectServerRef instead of a (ReflectServer *).
  o The ReflectServer class now derives from RefCountable
    and has an associated ReflectServerRef typedef.
  o Removed the SetOkayToClose*() methods from the 
    MessageTransceiverThread class, as they are no longer
    necessary.
  * BecomeDaemonProcess() now calls ExitWithoutCleanup()
    instead of exit(), to avoid crashing the parent process
    in the globals-cleanup phase (since the CompleteSetupSystem
    object destructor never gets a chance to run).
  * Replaced all calls to exit() with calls to 
    ExitWithoutCleanup().
  * Tweaked FileDescriptorDataIO to compile correctly on
    64-bit systems.
  * Fixed typedefs of int32/uint32 for the PPC64 platform.
  * Fixed typedef of muscle_socklen_t on PPC64
  * ZipFileUtilityFunctions.cpp was calling newnothrow to
    allocate an array.  Changed it to call newnothrow_array
    instead.
  * RefCount::SetFromGeneric() would return B_NO_ERROR if
    you tried to call SetFromGeneric(NullRef()), but it
    wouldn't actually change the state of the Ref that
    you called it on.  It now sets the state to NULL in
    that case.
  * AtomicCounter.h now uses the public QAtomicInt API
    when compiled with Qt 4.4.0 or higher.  (When compiling
    with Qt 4.0.0 through 4.3.x, it will still use the old 
    private atomic API)
  * Applied some tweaks to MuscleSupport.h for better
    MacOS/X Leopard compatibility.
  * Tweaked SharedMemory.h to compile on MacOS/X Leopard.