Multi User Server Client Linkage Environment v9.23

Open Source Software by Meyer Sound Laboratories Inc

Written by Jeremy Friesner, Last Updated 2/24/2023


Download the latest MUSCLE source and documentation (v9.23)

Go to the MUSCLE page on GitHub

Subscribe to the MUSCLE developer's mailing list

Watch a short video of a MUSCLE server synchronizing multiple clients in real time

Read the Beginner's Guide to MUSCLE

Take the self-guided learn-by-example API tour

Read the Guide to making a custom MUSCLE server

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

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


What is MUSCLE?

MUSCLE is a robust, scalable, efficient, 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, D-Mitri, Spacemap Go, and various other audio control applications at Meyer Sound Laboratories for over twenty years. With MUSCLE, you can:


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

key:  - new feature
      * bug fixed
      o other

9.23 - Release 2/24/2023
   - Added a -DWITH_THREAD_SANITIZER=ON option to the CMakeLists.txt.
   - Added a -DMUSCLE_NUM_RESERVED_HIGH_BITS_IN_POINTERS flag to specify
     how many of the most-significant-bits of a pointer are reserved for
     system use.  This value defaults to 16 for 64-bit Android systems
     (to account for Android's MTE feature) and to 0 on everything else.
   - Added a _registeredSubscribersMutex to the ICallbackMechanism class
     so that it can handle unusual dispatching cases more gracefully.
   - Added a runtests.sh script to tests folder.  This script can be
     run to quickly execute all tests and report any detected regressions.
   - Added add_test() directives to test/CMakeLists.txt to enable CTest.
   o Renamed -DMUSCLE_AVOID_BITSTUFFING to -DMUSCLE_AVOID_TAGGED_POINTERS
     since the latter is a more commonly-used term.
   o Changed the default setting of the WITH_TESTS option to OFF
     in CMakeLists.txt
   * GetNetworkInterfaceinfos() is now implemented for Android
     (API level 24 or later).
   * SharedMemory.cpp now compiles under Android (pre API level 26)
     although its methods will return B_UNIMPLEMENTED if called.
   * GetNetworkInterfaceInfos() now returns B_UNIMPLEMENTED when
     called from an OS that it doesn't have an implementation for.
   * Applied some Android build fixes as suggested by Ruurd Adema.
   * SetFileLogLevel() was broken.  Fixed.
   * Avoid including sem.h when MUSCLE_FAKE_SHARED_MEMORY is defined.

9.22 - Released 2/2/2023
   - Modified Queue::InternalizeIndex() to use subtraction
     instead of modulo, for a 3x efficiency gain.
   - Added a MUSCLE_NOEXCEPT keyword that expands to noexcept
     under C++11 or later, or to nothing under C++03
   - Added MUSCLE_NOEXCEPT tags to the SwapContents() methods
     and move-constructors/operators that can make that guarantee.
   - Added a MatchesNodeNameQueryFilter class, to support query
     filtering against DataNode-names.
   - Added DataNode::SetNodeName()
   - Added a WITH_IPV6=OFF option to the CMakeLists.txt for
     easier building of MUSCLE in IPv4-only mode.
   - Added a "shareport" argument to hexterm to enable UDP port-sharing.
   - Added an IsBroadcast() method to the IPAddress class.
   - Added GetStatus() and SetStatus() methods to the
     Ref/ConstRef/DummyRef/DummyConstRef classes, so that when they
     are returned in a NULL state they can tell you why they aren't set.
   - Added BooleansToBitChord() convenience-functions to PointerAndBits.h
   - Updated PointerAndBits to be able to use the high bit in a
     pointer as well as the low bit(s).
   - Updated the captive zlib library to v1.2.13.
   o Replaced the PointerAndBool.h header (and class) with a new
     PointerAndBits.h header (and class) that does the same thing,
     but in a simpler, more generalized fashion.
   * Fixed broken UDP support in hexterm when -DMUSCLE_AVOID_IPV6
     was set as a compiler-flag.
   * Renamed SOCKET_FAMILY_IPV6 to SOCKET_FAMILY_IPV6_IS_DISABLED
     when -DMUSCLE_AVOID_IPV6 is set, to avoid potential runtime bugs.

9.21 - Released 1/13/2023
   - Added @tparam Doxygen tags for any template-arguments that
     the calling code might need to specify explicitly.
   - Enabled tagfile generation in muscle.dox.
   - Added a DataIO::ReadFullyUpTo() convenience-method to handle
     reading (up to n) bytes or (until EOF), whichever comes first.
   - Added error code B_END_OF_STREAM to allow Read()-type methods
     to unambiguously specify that the reason they are returning an
     error is because they have reached EOF/EOS.
   o Changed DataIO::ReadFully() and DataIO::WriteFully() to
     return status_t instead of uint32.
   o Removed the C APIs from the Doxygen output.
   o Auto-updated the muscle.dox file to the latest Doxygen version.
   * Fixed several issues to make Doxygen's output more useful.
   * Fixed some compiler warnings in the captive regex library.
   * Fixed the namespacing of the DoxyTemplates header so that
     Doxygen generation works with the newest Doxygen version.
   * Updated a number of out-of-date Doxygen comments.

9.20 - Released 12/30/2022
   - Updated NetworkUtilityFunctions.cpp to better support "real"
     IPv4 sockets (previously it assumed that IPv4 traffic would
     be handled using IPv6 sockets and IPv4-mapped IPv6 addresses,
     but that approach doesn't give 100% compatibility in all cases)
   - Added a GetSocketFamily() method to the Socket class.
   - Added an optional (socketFamily) argument to CreateUDPSocket().
   - Added IsOK(io_status_t &) and IsError(io_status_t &) method
     overrides to the io_status_t class.
   - hexterm now instantiates a genuine IPv4 socket for use with
     IPv4 multicast traffic.
   - Tweaked gz*.c includes to compile without a configuration step.
   - Added input-data-timestamping (including a PR_NAME_DATA_TIMESTAMP
     field and SetReceiveTimestampingEnabled() and
     GetReceiveTimestampingEnabled() methods) to the
     RawDataMessageIOGateway class.
   - Added SetLogLevelThreshold() and GetLogLevelThreshold() arguments
     to the LogCallback class so that any LogCallback can now specify
     what log-levels it is (or is not) interested in.
   - Added templated overloads of Message::FindFlat(), Message::FindTag()
     Message::GetFlat(), and Message::GetTag() that take any type of Ref
     as an argument, so calling code no longer has to pass in a generic
     RefCountableRef or FlatCountableRef and then do the necessary
     downcasting separately afterward.
   - Message::FindTag() now takes a ConstRefCountableRef as an
     argument rather than a RefCountableRef, for better flexibility.
   - Added templated overloads of Message::AddFlat(), PrependFlat(),
     ReplaceFlat(), AddTag(), PrependTag(), and ReplaceTag() so that
     the calling code no longer has to do manual upcasting of typed
     FlatCountableRef or RefCountableRef objects before calling them.
   - Added ConstMessageRef overloads of InflateMessage() and DeflateMessage().
   - Added a ConstMessageRef-returning overload of Message::FindMessage().
   o Removed the ByteBufferRef-specific *Flat() methods from
     the Message class, since we now have more general templatized
     methods that offer the same semantics for any type.
   o SocketMultiplexer::WaitForEvents() now returns an io_status_t
     rather than an int, for better error-reporting.
   o Merged the IPv6 and IPv4 versions of AddSocketToMulticastGroup()
     and RemoveSocketFromMulticastGroup() so that a single implementation
     can work on either type of socket.
   o Renamed SetSocketMulticastSendInterfaceAddress() and
     GetSocketMulticastSendInterfaceAddress() to
     SetIPv4SocketMulticastSendInterfaceAddress() and
     GetIPv4SocketMulticastSendInterfaceAddress(), respectively,
     and made them available even when -DMUSCLE_AVOID_IPV6 isn't set.
   o Renamed Log() to LogPlain().
   o Made LogTime() and LogPlain() into macros so that their arguments
     will not be evaluated unless the logging-threshold-test passes.
   o Improved error reporting in the ReflectServer event-loop.
   o Removed the functions from TimeUnitConversions.h that take
     (struct timeval &) as their argument, since they weren't being used.
   o Removed SetConsoleLogLevel() and GetConsoleLogLevel() from the
     DefaultConsoleLogger class, in favor of the new equivalent methods
     in the LogCallback base class.
   o Removed SetFileLogLevel() and GetFileLogLevel() from the
     DefaultFileLogger class, in favor of the new equivalent methods
     in the LogCallback base class.
   o Renamed muscle's private namespaces to muscle_private.
   o Replaced long with int32 in some I/O support functions.
   o The default ByteBufferPool now clears the IMemoryAllocationStrategy
     field of any ByteBuffer it recycles (after freeing its memory),
     to avoid polluting the pool with user-installed strategies.
   o Ref::SetFromRefCountableRef() now returns B_TYPE_MISMATCH on failure
     rather than B_BAD_ARGUMENT.
   o Removed the two-argument ConstRef and Ref "pseudo-constuctors"
     and added instead a DowncastTo() method, to
     make Ref-downcasting operations self-documenting.
   o Changed ITraversalPruner::MatchPath() and CreateObjectFromArchiveMessage()
     to take ConstMessageRef as an argument rather than MessageRef.
   o Changed StorageReflectSession::SetDataNode(), InsertOrderedData(),
     InsertOrderedChildNode(), and GetNewDataNode() to take
     ConstMessageRef as an argument rather than MessageRef.
   o Changed DataNode to hold a ConstMessageRef rather than a MessageRef.
   o Changed StorageReflectSession::NotifySubscribersThatNodeChanged()
     and StorageReflectSession::NodeChanged() to pass a ConstMessageRef
     rather than a MessageRef.
   o ByteBuffer::ReleaseBuffer() now returns (uint8 *) instead of
     (const uint8 *).
   * Fixed MLOG_ON_ERROR and friends to be usable with io_status_t.
   * ExpandLocalhostAddress() no longer expands IPv6 loopback addresses.
   * UDPSocketDataIO::ReadFrom() would call SetSourceOfLastReadPacket()
     even when no packet had been read, clearing that field.  Fixed.
   * Some functions in MuscleSupport.h were unintentionally being
     declared outside the muscle namespace.  Fixed.

9.10 - Released 12/10/2022
   - Rewrote the non-Windows implementation of muscleSprintf()
     to call vsnprintf() instead of sprintf(), to avoid compiler
     warnings about sprintf() being insecure.
   - Instrumented the non-Windows implementation of muscleSprintf()
     with MUSCLE_PRINTF_ARGS_ANNOTATION_PREFIX so that the compiler
     will warn about calls to muscleSprintf() with the wrong format
     specifiers.
   - Added an io_status_t class to represent the result of an I/O
     operation.  An io_status_t contains both a status_t and an
     int32 byte-count.
   - Added a MUSCLE-by-example page for the status_t class.
   - Added MTALLY_BYTES_OR_RETURN_ON_IO_ERROR() and
     MTALLY_BYTES_OR_RETURN_ON_IO_ERROR_OR_BREAK() macros to
     MuscleSupport.h.
   o Changed the return-types of the NetworkUtilityFunctions that
     previously returned (int32/byte-count-or-negative-1), aka
     SendData(), ReceiveData(), SendDataUDP(), ReceiveDataUDP(),
     ReadData(), and WriteData() to return a more informative
     io_status_t instead.
   o Changed the DataIO::Read() and DataIO::Write() methods to
     return io_status_t instead of int32.
   o Changed the PacketDataIO::ReadFrom() and PacketDataIO::WriteTo()
     methods to return io_status_t instead of int32.
   o Simplified the implementation of GetDefaultObjectForType() back
     to one that compile under any version of C++.  We'll rely on
     the optimizer to do the right thing, rather than SFINAE.
   o Modified Directory::SetDir() to return a static status_t value
     rather than B_ERRNO, to avoid potential static-initialization
     ordering problems on pre-C++11 compilers.
   o tagged status_t as a MUSCLE_FINAL_CLASS.
   o Replaced the MAKETYPE(x) macro with a MakeWhatCode() function.
   * Updated message_transceiver_thread.py to catch and ignore any
     EAGAIN exceptions generated by send() on a notification-socket.
   * Fixed a spurious assertion failure in SimulatedMulticastDataIO.
   * Changed some code to return B_IO_ERROR instead of B_ERRNO if
     fread() or fwrite() fails, since those functions are not
     guaranteed to set errno when they fail.
   * Fixed a bug that would cause GetEnvironmentVariableValue() to
     sometimes return garbage strings under Windows if the environment
     variable did not exist.
   * Added missing DOxygen parameter documentation for various
     macros declared in MuscleSupport.h.
   * Fixed a number of broken hyperlinks in the MUSCLE-by-example docs.

9.01 - Released 11/18/2022
   - Added a WritePaddingBytesToAlignTo(uint32 alignSize)
     convenience-method to the CheckedDataFlattenerHelper
     and DataFlattenerHelper classes.
   - Added a SeekPastPaddingBytesToAlignTo(uint32 alignSize)
     convenience-method to the DataUnflattenerHelper class.
   - Added DataUnflattener ctor and SetBuffer() calls that
     take a ByteBufferRef, for convenience.
   - Added a GetEnvironmentVariableValue() convenience function,
     to avoid calling getenv() directly from user code.
   - Added %p (aka process ID) to the set of tokens expanded by
     HumanReadableTimeValues::ExpandTokens().
   - DefaultFileLogger::EnsureLogFileCreated() now tries a little
     harder: if it can't create a log file with the given file name,
     it will try up to 10 variants of the file name in the hopes
     of coming up with a file name that is unique and can be created.
   - Added a IsBitIndexValid() convenience-method to the BitChord class.
   - Added MUSCLE_CONSTEXPR_OR_CONST macro to expand to "constexpr"
     if possible, or "const" otherwise.
   - GetDefaultObjectForType() now uses constexpr to avoid on-demand
     initialization, when -DMUSCLE_USE_CPLUSPLUS17 is defined.
   - CMakeLists.txt now automatically specifies -DMUSCLE_USE_PTHREADS
     if building on POSIX for C++03, and WITH_THREADS is ON.
   - LogTime() calls now emit printf-style format-usage warnings
     when compiled with g++ or clang++.
   - Added INT16_FORMAT_SPEC_* macros, for completeness.
   o PODSwapper now calls std::swap() rather than reimplementing it.
   * Moved the definitions of the B_* error-codes out of SetupSystem.cpp
     and into MuscleSupport.h, so that Clang's Static Analyzer can see
     what values they contain and generate better output.
   * Generation of the random number that %r expands to is now
     actually random (not just calling rand()) (in C++11 or newer).
   * Renamed several of the longer mkdocs examples folder names
     to avoid hitting Windows' 260-character path limit.
   * Fixed a potential uninitialized-memory-read in the String
     class's GetLevenshteinDistance() method.
   * Fixed the CMakeList.txt files in the sub-folders to use
     the inherited CMAKE_CXX_STANDARD setting rather than
     forcing C++11.
   * GetCurrentThreadID() is no longer compiled if
     -DMUSCLE_SINGLE_THREAD_ONLY is specified.

9.00 - Released 10/27/2022
   - Added a MUSCLE_MAXIMUM_NODE_DEPTH constant that limits
     how deep the MUSCLE node-tree may become, to prevent
     stack-overflow attacks.  Defaults to 100.
   - Added DataFlattener and DataUnflattener classes to
     allow for safer flattening/unflattening of data
     to/from byte-buffers.
   - Added an UncheckedDataUnflattener class, for better
     efficiency when the calling code has already done its
     own bounds-checking.
   - Added a CheckedDataUnflattener class, for better
     calling code that wants to use a dynamically-growing
     output buffer.
   - Added support/EndianConverter.h to allow templating
     over big/little/native endian-encoding strategies.
   - Added pages for DataFlattener and DataUnflattener
     APIs to the muscle-by-example documentation.
   - Adding -DMUSCLE_USE_BIG_ENDIAN_DATA_FOR_EVERYTHING
     to your compile line will tell MUSCLE to use big-endian
     data format for all of its data.  Note that doing so will
     break interoperability with all existing MUSCLE builds!
   - Adding -DMUSCLE_USE_NATIVE_ENDIAN_DATA_FOR_EVERYTHING
     to your compile line will tell MUSCLE to use native-endian
     data format for all of its data.  Note that doing so will
     break compatibility with different-endian CPUs!
   o Changed the PseudoFlattenable::Flatten() and
     Flattenable::Flatten() methods to take a second
     argument (flatSize) for better runtime error-checking.
   o Changed the PseudoFlattenable::Unflatten() and
     Flattenable::Unflatten() methods to take a
     (DataUnflattener &) as an argument rather than
     a raw pointer, for better caller/callee cooperation.
   o Changed Message::TemplatedFlatten() to use
     a DataFlattener as an argument.
   o Changed Message::TemplatedUnflatten() to use
     a DataUnflattener as an argument.
   o Removed the SetEndianFlag(), Append*(), Write*(),
     Read*() methods from the ByteBuffer class.  Use
     the new DataFlattener/DataUnflattener classes instead.
   o Refactored the StringTokenizer class's constructors to
     take a single (optSepChars) argument instead of separate
     arguments for hard and soft separator characters.
   o Made the calculation of DataNode depths more efficient.
   o Removed Flattenable::WriteData() and Flattenable::ReadData()
     methods (since DataFlattener/DataUnflattener do it better).
   o Replaced most calls to B_LENDIAN_*_TO_HOST() and
     B_HOST_TO_LENDIAN_*() with calls to DefaultEndianConverter's
     Import() and Export() methods, to allow MUSCLE to be built
     in big-endian mode.
   o Changed the PseudoFlattenable class to be templatized, and
     added methods to it so all the helper methods declared in
     the Flattenable interface are also available in the
     PseudoFlattenable interface.
   o Refactored the ZLib-support classes in muscle/zlib so that they
     no longer include any zlib-headers from their header files.
   * Modified Snooze64() to call clock_nanosleep() under Linux,
     and to call nanosleep() when -DMUSCLE_USE_LIBRT is defined.
   * Changed all the #include "zlib/zlib/zlib.h" directives to
     #include "zlib.h" to avoid using the captive zlib headers
     together with any system-supplied zlib implementation (which
     might be different)
   * Fixed a bug that could cause ZLibDataIO::WriteAux() to
     to into an infinite recursion if zlib's deflate() errored out.
   * Fixed a bug in MessageIOGateway that could cause it fail
     to report how many bytes it had sent or received, if an
     I/O error occurred later on in the same call to DoInput()
     or DoOutput().