Traced the dispatched-message delivery end to end with BT_MP_NET / BT_MP_FORCE_DMG. Everything works except one wire step: - A's Entity::Dispatch reroutes the replicant's TakeDamage (application->SendMessage(ownerID=3, EntityManager, msg)); POST-Dispatch the message carries entityID=3:22 (host:local) -- the replicant's own ID, matching B's master (GetEntityID()==3:22). VERIFIED sent. - On B the message ARRIVES, GetEntityPointer finds an entity, Posts it, the event drains (ProcessEventTask = ProcessOneEvent(0)), Event::Process runs, Receive finds+calls a handler. VERIFIED the full deliver chain. - BUG: B receives entityID=3:19, NOT 3:22 -- the localID dropped by exactly the hostID (3) between A's send and B's receive. So GetEntityPointer(3:19) returns the WRONG entity (classID 48, not the mech 0xBB9), whose base handler ignores the unaimed hit -> 0 damage. Auto-replicated UPDATE records (msgID 18) arrive with the correct 3:22 and find the mech, so the corruption is specific to the dispatched- message wire path/direction. Next: the host-relative EntityID (de)serialization on the dispatched-msg path (RoutePacket / packet EntityID encoding) -- diff vs the update path which translates correctly. Diagnostics retained (all BT_MP_NET-gated, off in solo -- verified: solo 22 hits, 0 probe noise). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
652 lines
16 KiB
C++
652 lines
16 KiB
C++
#include "munga.h"
|
|
#pragma hdrstop
|
|
|
|
#include "receiver.h"
|
|
#include "event.h"
|
|
|
|
//#############################################################################
|
|
//############################# Receiver ################################
|
|
//#############################################################################
|
|
|
|
const Receiver::Handler
|
|
Receiver::NullHandler=NULL;
|
|
|
|
Receiver::SharedData
|
|
Receiver::DefaultData(
|
|
Receiver::GetClassDerivations(),
|
|
Receiver::GetMessageHandlers()
|
|
);
|
|
|
|
Derivation* Receiver::GetClassDerivations()
|
|
{
|
|
static Derivation classDerivations("Receiver");
|
|
return &classDerivations;
|
|
}
|
|
|
|
const Receiver::HandlerEntry
|
|
Receiver::MessageHandlerEntries[]=
|
|
{
|
|
{
|
|
Receiver::WatcherChangedMessageID,
|
|
"WatcherChanged",
|
|
(Receiver::Handler)&Receiver::DefaultMessageHandler
|
|
},
|
|
{
|
|
Receiver::LoadResourceFinishedMessageID,
|
|
"LoadResourceFinished",
|
|
(Receiver::Handler)&Receiver::DefaultMessageHandler
|
|
}
|
|
};
|
|
|
|
Receiver::MessageHandlerSet& Receiver::GetMessageHandlers()
|
|
{
|
|
static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(Receiver::MessageHandlerEntries), Receiver::MessageHandlerEntries);
|
|
return messageHandlers;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
#if defined(USE_SIGNATURE)
|
|
int
|
|
Is_Signature_Bad(const volatile Receiver__Message *)
|
|
{
|
|
return False;
|
|
}
|
|
#endif
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
#if DEBUG_LEVEL>0
|
|
Receiver::DefaultMessageHandler(Message* message)
|
|
#else
|
|
Receiver::DefaultMessageHandler(Message*)
|
|
#endif
|
|
{
|
|
Tell(
|
|
"Default Handler activated on message ID " << message->messageID << endl
|
|
);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Receiver::Receive(Message *what)
|
|
{
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Service the message taps by creating an iterator to step through all the
|
|
// MessageTaps registered with the Derivation object for the receiver's
|
|
// class. Each tap will do whatever it thinks best about this receiver
|
|
// having received this message
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
Check(this);
|
|
Check_Pointer(what);
|
|
ChainIteratorOf<MessageTap*> i(GetDerivation()->activeTaps);
|
|
MessageTap *tap;
|
|
while ((tap = i.ReadAndNext()) != NULL)
|
|
{
|
|
tap->Scan(this,what);
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Now, see if the receiver can handle this type of message, and if so, send
|
|
// the message to the returned method handler
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Receiver::SharedData *sharedData = GetSharedData();
|
|
Handler handler = sharedData->activeMessageHandlers->Find(what->messageID);
|
|
// MP DIAGNOSTIC (task #47): for a TakeDamage (msgID 21), report whether a
|
|
// handler is found on this receiver (the cross-pod delivery endpoint).
|
|
if (what->messageID == 21 && getenv("BT_MP_NET"))
|
|
DEBUG_STREAM << "[mp-recv2] Receive TakeDamage this=" << (void*)this
|
|
<< " handler=" << (handler != Receiver::NullHandler ? "FOUND" : "NULL")
|
|
<< "\n" << std::flush;
|
|
if (handler != Receiver::NullHandler)
|
|
{
|
|
(this->*handler)(what);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Receiver::Receive(Event *event)
|
|
{
|
|
Receive(event->messageToSend);
|
|
Unregister_Object(event);
|
|
delete event;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Receiver::FlushEvents(int) // max_priority doesn't work yet!!!!
|
|
{
|
|
Check(this);
|
|
PlugIteratorOf<Event*> i(this);
|
|
Event *event;
|
|
while ((event = i.ReadAndNext()) != NULL)
|
|
{
|
|
if (event->GetClassID() == EventClassID)
|
|
{
|
|
Unregister_Object(event);
|
|
delete event;
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Receiver::FlushMatchingEvents(
|
|
Receiver::MessageID target_message,
|
|
int // max_priority doesn't work yet!!!!
|
|
)
|
|
{
|
|
Check(this);
|
|
PlugIteratorOf<Event*>
|
|
i(this);
|
|
Event* event;
|
|
while ((event = i.ReadAndNext()) != NULL)
|
|
{
|
|
if (
|
|
event->GetClassID() == EventClassID && (
|
|
target_message == Receiver::AnyMessageID
|
|
|| event->messageToSend->messageID == target_message
|
|
)
|
|
)
|
|
{
|
|
Unregister_Object(event);
|
|
delete event;
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Receiver::ProcessDeferredQueue()
|
|
{
|
|
//
|
|
//------------------------------------------------
|
|
// Find a delay queue, and return if there is none
|
|
//------------------------------------------------
|
|
//
|
|
Check(this);
|
|
PlugIteratorOf<DeferredEventQueue*> i(this);
|
|
DeferredEventQueue *deferred_queue;
|
|
while ((deferred_queue = i.ReadAndNext()) != NULL)
|
|
{
|
|
if (deferred_queue->GetClassID() == DeferredEventQueueClassID)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (!deferred_queue)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------
|
|
// Now, tell the queue to process all its events, then delete it
|
|
//--------------------------------------------------------------
|
|
//
|
|
deferred_queue->ProcessAllEvents();
|
|
Unregister_Object(deferred_queue);
|
|
delete deferred_queue;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
Receiver::TestInstance() const
|
|
{
|
|
return IsDerivedFrom(*GetClassDerivations());
|
|
}
|
|
|
|
//#############################################################################
|
|
//######################### Receiver::Message ###########################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
Receiver::Message::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
//#############################################################################
|
|
//######################### Receiver::DynamicMessage ##########################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Receiver__DynamicMessage::Receiver__DynamicMessage(
|
|
Receiver::MessageID message_ID,
|
|
size_t message_size
|
|
)
|
|
{
|
|
Receiver::Message new_message(message_ID, message_size);
|
|
WriteBytes(&new_message, message_size);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MemoryStream&
|
|
Receiver::DynamicMessage::WriteBytes(
|
|
const void *ptr,
|
|
size_t number_of_bytes
|
|
)
|
|
{
|
|
DynamicMemoryStream::WriteBytes(ptr, number_of_bytes);
|
|
|
|
Receiver::Message *message = GetMessagePointer();
|
|
size_t new_size = GetBytesUsed();
|
|
message->messageLength = new_size;
|
|
return *this;
|
|
}
|
|
|
|
//#############################################################################
|
|
//############################ MessageTap ###############################
|
|
//#############################################################################
|
|
|
|
MemoryBlock *MessageTap::GetAllocatedMemory()
|
|
{
|
|
static MemoryBlock allocatedMemory(sizeof(MessageTap), 30, 30, "Message Taps");
|
|
return &allocatedMemory;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MessageTap::MessageTap(
|
|
Derivation *derivation,
|
|
Receiver *client,
|
|
Receiver::ScanCallback call_back
|
|
):
|
|
Plug(MessageTapClassID)
|
|
{
|
|
//
|
|
//---------------------------
|
|
// Initialize the message tap
|
|
//---------------------------
|
|
//
|
|
Check(client);
|
|
clientReceiver = client;
|
|
scanCallback = call_back;
|
|
matchingReceiver = NULL;
|
|
matchingMessageID = Receiver::AnyMessageID;
|
|
|
|
//
|
|
//--------------------------------------------
|
|
// Hook the tap up to the specified derivation
|
|
//--------------------------------------------
|
|
//
|
|
Check(derivation);
|
|
derivation->AppendMessageTap(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MessageTap::MessageTap(
|
|
Derivation *derivation,
|
|
Receiver *client,
|
|
Receiver::ScanCallback call_back,
|
|
Receiver::MessageID messageID,
|
|
Receiver *receiver
|
|
):
|
|
Plug(MessageTapClassID)
|
|
{
|
|
//
|
|
//---------------------------
|
|
// Initialize the message tap
|
|
//---------------------------
|
|
//
|
|
Check(client);
|
|
clientReceiver = client;
|
|
scanCallback = call_back;
|
|
|
|
matchingReceiver = receiver;
|
|
matchingMessageID = messageID;
|
|
|
|
//
|
|
//--------------------------------------------
|
|
// Hook the tap up to the specified derivation
|
|
//--------------------------------------------
|
|
//
|
|
Check(derivation);
|
|
derivation->AppendMessageTap(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
MessageTap::Scan(
|
|
Receiver *receiver,
|
|
Receiver::Message *message
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
|
|
if (
|
|
(!matchingReceiver || matchingReceiver == receiver)
|
|
&& (
|
|
matchingMessageID == Receiver::AnyMessageID
|
|
|| matchingMessageID == message->messageID
|
|
)
|
|
)
|
|
{
|
|
(clientReceiver->*scanCallback)(message,receiver);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
MessageTap::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
//#############################################################################
|
|
//##################### Receiver::InheritanceSet ########################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
Receiver::InheritanceSet::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
//#############################################################################
|
|
//#################### Receiver::MessageHandlerSet ######################
|
|
//#############################################################################
|
|
|
|
const Receiver::MessageHandlerSet
|
|
Receiver::MessageHandlerSet::NullSet;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Receiver__MessageHandlerSet::~Receiver__MessageHandlerSet()
|
|
{
|
|
if (messageHandlers)
|
|
{
|
|
Unregister_Pointer(messageHandlers);
|
|
delete[] messageHandlers;
|
|
messageHandlers = NULL;
|
|
}
|
|
};
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Receiver::MessageHandlerSet::Build(
|
|
Receiver::MessageID count,
|
|
const Receiver::HandlerEntry handler_table[],
|
|
const Receiver::MessageHandlerSet *inheritance
|
|
)
|
|
{
|
|
//
|
|
//-------------------------------------------------------
|
|
// Find out the highest message type we have to deal with
|
|
//-------------------------------------------------------
|
|
//
|
|
Check(this);
|
|
Check_Pointer(handler_table);
|
|
entryCount = 0;
|
|
Receiver::MessageID i;
|
|
for (i=0; i<count; ++i)
|
|
{
|
|
if (handler_table[i].entryID > entryCount)
|
|
{
|
|
entryCount = handler_table[i].entryID;
|
|
}
|
|
}
|
|
if (inheritance)
|
|
{
|
|
Check(inheritance);
|
|
if (entryCount < inheritance->entryCount)
|
|
{
|
|
entryCount = inheritance->entryCount;
|
|
}
|
|
#if DEBUG_LEVEL>0
|
|
else if (entryCount > inheritance->entryCount)
|
|
{
|
|
i = inheritance->entryCount+1;
|
|
goto Check_Table;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
Verify(entryCount == count);
|
|
#if DEBUG_LEVEL>0
|
|
i = 1;
|
|
Check_Table:
|
|
while (i <= entryCount)
|
|
{
|
|
int j;
|
|
for (j=0; j<count; ++j)
|
|
{
|
|
if (handler_table[j].entryID == i)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (j == count)
|
|
{
|
|
break;
|
|
}
|
|
++i;
|
|
}
|
|
Verify(i > count);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Allocate the memory for the new handler set, and copy the inherited
|
|
// handlers to the new table. We are guaranteed to have enough space for
|
|
// the inherited table
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
messageHandlers = new Receiver::HandlerEntry[entryCount];
|
|
Check_Pointer(messageHandlers);
|
|
Register_Pointer(messageHandlers);
|
|
i = 0;
|
|
if (inheritance)
|
|
{
|
|
for (; i<inheritance->entryCount; ++i)
|
|
{
|
|
messageHandlers[i] = inheritance->messageHandlers[i];
|
|
}
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Step through the new table supplied, placing each handler in the slot
|
|
// determined by the message type
|
|
//----------------------------------------------------------------------
|
|
//
|
|
for (i=0; i<count; ++i)
|
|
{
|
|
Receiver::MessageID index = handler_table[i].entryID - 1;
|
|
Verify(index >= 0 && index < entryCount);
|
|
messageHandlers[index] = handler_table[i];
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const Receiver::HandlerEntry*
|
|
Receiver::MessageHandlerSet::Find(const char* name) const
|
|
{
|
|
Check(this);
|
|
Check_Pointer(name);
|
|
|
|
for (int i=0; i<entryCount; ++i)
|
|
{
|
|
if (!strcmp(name, messageHandlers[i].entryName))
|
|
{
|
|
return &messageHandlers[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//#############################################################################
|
|
//############################# Derivation ##############################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Derivation::Derivation(char *name):
|
|
Node(DerivationClassID),
|
|
classDerivations(this),
|
|
activeTaps(this)
|
|
{
|
|
Dump(name);
|
|
className = name;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Derivation::Derivation(
|
|
Derivation *derivation,
|
|
char *name
|
|
):
|
|
Node(DerivationClassID),
|
|
classDerivations(this),
|
|
activeTaps(this)
|
|
{
|
|
//
|
|
//----------------------------------------------------------
|
|
// Add this derivation as a child of the parent's derivation
|
|
//----------------------------------------------------------
|
|
//
|
|
Dump(name);
|
|
className = name;
|
|
Check(derivation);
|
|
if (derivation)
|
|
derivation->AppendDerivation(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Derivation::AppendMessageTap(MessageTap* tap)
|
|
{
|
|
Check(this);
|
|
Check(tap);
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Add the tap to the taps chain, then step through all our derivations,
|
|
// sending each of them this same method
|
|
//----------------------------------------------------------------------
|
|
//
|
|
activeTaps.Add(tap);
|
|
ChainIteratorOf<Derivation*>
|
|
i(classDerivations);
|
|
Derivation *derivation;
|
|
while ((derivation = i.ReadAndNext()) != NULL)
|
|
{
|
|
derivation->AppendMessageTap(tap);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
Derivation::IsDescendedFrom(Derivation& parent)
|
|
{
|
|
Check(this);
|
|
Check(&parent);
|
|
|
|
//
|
|
//------------------------------
|
|
// We are descended from ourself
|
|
//------------------------------
|
|
//
|
|
if (&parent == this)
|
|
{
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Find our parent derivation, and ask him
|
|
// sending each of them this same method
|
|
//----------------------------------------------------------------------
|
|
//
|
|
PlugIteratorOf<Derivation*> i(this);
|
|
Derivation *derivation;
|
|
while ((derivation = i.ReadAndNext()) != NULL)
|
|
{
|
|
if (derivation->GetClassID() == DerivationClassID)
|
|
{
|
|
return derivation->IsDescendedFrom(parent);
|
|
}
|
|
}
|
|
return False;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
Derivation::IsDescendedFrom(const char* parent)
|
|
{
|
|
Check(this);
|
|
Check_Pointer(parent);
|
|
|
|
//
|
|
//------------------------------
|
|
// We are descended from ourself
|
|
//------------------------------
|
|
//
|
|
Check_Pointer(className);
|
|
if (!strcmp(className, parent))
|
|
{
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Find our parent derivation, and ask him
|
|
// sending each of them this same method
|
|
//----------------------------------------------------------------------
|
|
//
|
|
PlugIteratorOf<Derivation*> i(this);
|
|
Derivation *derivation;
|
|
while ((derivation = i.ReadAndNext()) != NULL)
|
|
{
|
|
Check(derivation);
|
|
if (derivation->GetClassID() == DerivationClassID)
|
|
{
|
|
return derivation->IsDescendedFrom(parent);
|
|
}
|
|
}
|
|
return False;
|
|
}
|
|
|
|
//#############################################################################
|
|
//###################### Receiver::SharedData ##########################
|
|
//#############################################################################
|
|
|
|
Logical
|
|
Receiver::SharedData::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
#if defined(TEST_CLASS)
|
|
# include "receiver.tcp"
|
|
#endif
|