Written by Jeremy Friesner, Last Updated 4/28/2008
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 BeShare and MUSCLE BeNews article
MUSCLE is licensed under the BSD Open Source License
Study the Java Client API Javadocs
Download previous versions of MUSCLE
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.