/* * Modification History * * 2003-July-20 Jason Rohrer * Created. * * 2003-August-25 Jason Rohrer * Added support for registering message handler functions. * * 2003-October-7 Jason Rohrer * Added missing call to unlock. * Added separate locks for handlers and receive addresses to fix deadlocks. * Fixed bug in address removal function. * Removed print statements. * * 2003-December-5 Jason Rohrer * Added support for message utility. * * 2004-January-11 Jason Rohrer * Fixed locking bugs in destructor. */ #include "LocalAddressReceiver.h" #include "minorGems/util/stringUtils.h" LocalAddressReceiver::LocalAddressReceiver() : mHandlerLock( new MutexLock() ), mReceiveAddressLock( new MutexLock() ), mAddressVector( new SimpleVector() ), mNextFreeHandlerID( 0 ), mMessageHandlerVector( new SimpleVector() ), mMessageQueueVector( new SimpleVector< SimpleVector* >() ), mFromAddressQueueVector( new SimpleVector< SimpleVector* >() ) { } LocalAddressReceiver::~LocalAddressReceiver() { mReceiveAddressLock->lock(); int numAddresses = mAddressVector->size(); int i; for( i=0; igetElement( i ) ); SimpleVector *currentMessageQueue = *( mMessageQueueVector->getElement( i ) ); SimpleVector *currentFromAddressQueue = *( mFromAddressQueueVector->getElement( i ) ); int numInQueue = currentMessageQueue->size(); for( int j=0; jgetElement( j ) ); delete [] *( currentFromAddressQueue->getElement( j ) ); } delete currentMessageQueue; delete currentFromAddressQueue; } delete mAddressVector; delete mMessageQueueVector; delete mFromAddressQueueVector; mReceiveAddressLock->unlock(); mHandlerLock->lock(); int numHandlers = mMessageHandlerVector->size(); for( i=0; igetElement( i ) ); delete wrapper; } delete mMessageHandlerVector; mHandlerLock->unlock(); delete mHandlerLock; delete mReceiveAddressLock; } int LocalAddressReceiver::findAddressIndex( char *inAddress ) { int numAddresses = mAddressVector->size(); for( int i=0; igetElement( i ) ); if( strcmp( otherAddress, inAddress ) == 0 ) { return i; } } // not found return -1; } void LocalAddressReceiver::addReceiveAddress( char *inAddress ) { mReceiveAddressLock->lock(); // make sure address not already added int index = findAddressIndex( inAddress ); if( index != -1 ) { mReceiveAddressLock->unlock(); return; } // add address and a message queue mAddressVector->push_back( stringDuplicate( inAddress ) ); mMessageQueueVector->push_back( new SimpleVector() ); mFromAddressQueueVector->push_back( new SimpleVector() ); mReceiveAddressLock->unlock(); } void LocalAddressReceiver::removeReceiveAddress( char *inAddress ) { mReceiveAddressLock->lock(); int index = findAddressIndex( inAddress ); if( index != -1 ) { delete [] *( mAddressVector->getElement( index ) ); mAddressVector->deleteElement( index ); SimpleVector *currentMessageQueue = *( mMessageQueueVector->getElement( index ) ); SimpleVector *currentFromAddressQueue = *( mFromAddressQueueVector->getElement( index ) ); int numInQueue = currentMessageQueue->size(); for( int j=0; jgetElement( j ) ); delete [] *( currentFromAddressQueue->getElement( j ) ); } delete currentMessageQueue; delete currentFromAddressQueue; mMessageQueueVector->deleteElement( index ); mFromAddressQueueVector->deleteElement( index ); } mReceiveAddressLock->unlock(); } char LocalAddressReceiver::messageReceived( char *inFromAddress, char *inToAddress, char *inBody, int *outUtilityGenerated ) { mReceiveAddressLock->lock(); int index = findAddressIndex( inToAddress ); if( index != -1 ) { // received locally // track the utility that our handlers generate for this message int utility = 0; mHandlerLock->lock(); int numHandlers = mMessageHandlerVector->size(); if( numHandlers <= 0 ) { mHandlerLock->unlock(); // no handlers, so queue messages SimpleVector *currentMessageQueue = *( mMessageQueueVector->getElement( index ) ); SimpleVector *currentFromAddressQueue = *( mFromAddressQueueVector->getElement( index) ); currentMessageQueue->push_back( stringDuplicate( inBody ) ); currentFromAddressQueue->push_back( stringDuplicate( inFromAddress ) ); mReceiveAddressLock->unlock(); } else { // pass message to each handler // unlock so that handlers can modify receive addresses mReceiveAddressLock->unlock(); for( int i=0; igetElement( i ) ); utility += wrapper->mHandlerFunction( inFromAddress, inToAddress, inBody, wrapper->mExtraHandlerArgument ); } mHandlerLock->unlock(); } // message was received locally *outUtilityGenerated = utility; return true; } else { mReceiveAddressLock->unlock(); *outUtilityGenerated = 0; return false; } } int LocalAddressReceiver::addMessageHandler( int (*inHandlerFunction)( char *, char *, char *, void * ), void *inExtraHandlerArgument ) { mHandlerLock->lock(); int id = mNextFreeHandlerID; mNextFreeHandlerID++; MessageHandlerWrapper *wrapper = new MessageHandlerWrapper(); wrapper->mHandlerID = id; wrapper->mHandlerFunction = inHandlerFunction; wrapper->mExtraHandlerArgument = inExtraHandlerArgument; mMessageHandlerVector->push_back( wrapper ); mHandlerLock->unlock(); return id; } void LocalAddressReceiver::removeMessageHandler( int inHandlerID ) { mHandlerLock->lock(); int numHandlers = mMessageHandlerVector->size(); char found = false; for( int i=0; igetElement( i ) ); if( wrapper->mHandlerID == inHandlerID ) { mMessageHandlerVector->deleteElement( i ); delete wrapper; found = true; } } mHandlerLock->unlock(); } unsigned int LocalAddressReceiver::getWaitingMessageCount( char *inAddress ) { mReceiveAddressLock->lock(); int index = findAddressIndex( inAddress ); unsigned int returnValue; if( index != -1 ) { SimpleVector *currentMessageQueue = *( mMessageQueueVector->getElement( index ) ); returnValue = currentMessageQueue->size(); } else { returnValue = 0; } mReceiveAddressLock->unlock(); return returnValue; } unsigned int LocalAddressReceiver::getReceivedMessages( char *inAddress, unsigned int inNumMessages, char ***outMessages, char ***outFromAddresses ) { mReceiveAddressLock->lock(); int index = findAddressIndex( inAddress ); int returnValue; char **messages; char **fromAddresses; if( index != -1 ) { SimpleVector *currentMessageQueue = *( mMessageQueueVector->getElement( index ) ); SimpleVector *currentFromAddressQueue = *( mFromAddressQueueVector->getElement( index) ); int numToGet = inNumMessages; int numAvailable = currentMessageQueue->size(); if( numToGet > numAvailable ) { numToGet = numAvailable; } messages = new char*[numToGet]; fromAddresses = new char*[numToGet]; for( int i=0; igetElement(0) ); fromAddresses[i] = *( currentFromAddressQueue->getElement(0) ); currentMessageQueue->deleteElement( 0 ); currentFromAddressQueue->deleteElement( 0 ); } returnValue = numToGet; } else { returnValue = 0; messages = new char*[0]; fromAddresses = new char*[0]; } *outMessages = messages; *outFromAddresses = fromAddresses; mReceiveAddressLock->unlock(); return returnValue; }