bool SendHeartbeat (bool bWithStash) { LOGDEBUG (TEXT ("Sending heartbeat message")); FudgeStatus status; FudgeMsg msg; if ((status = FudgeMsg_create (&msg)) != FUDGE_OK) { LOGFATAL (TEXT ("Couldn't create message, status ") << status); assert (0); return false; } if ((status = ConnectorMessage_setOperation (msg, HEARTBEAT)) != FUDGE_OK) { FudgeMsg_release (msg); LOGFATAL (TEXT ("Couldn't create message, status ") << status); assert (0); return false; } if (bWithStash) { m_oStashMutex.Enter (); if (m_msgStash) { if ((status = ConnectorMessage_setStash (msg, m_msgStash)) != FUDGE_OK) { LOGFATAL (TEXT ("Couldn't create message, status ") << status); assert (0); status = FUDGE_OK; // Not good, but can carry on } } m_oStashMutex.Leave (); } bool bResult = m_poService->Send (MESSAGE_DIRECTIVES_CLIENT, msg); FudgeMsg_release (msg); return bResult; }
void Run () { int nAttempt = 0; CNamedPipe *poPipe; do { if (nAttempt) { Sleep (TIMEOUT / 10); } poPipe = CNamedPipe::ClientWrite (m_pszPipeName); } while (!poPipe && (GetLastError () == ENOENT) && (++nAttempt < 10)); if (poPipe) { LOGDEBUG (TEXT ("Client connected")); ClientConnect cc; memset (&cc, 0, sizeof (cc)); cc._userName = TEST_USERNAME; cc._CPPToJavaPipe = TEST_CPP2JAVA; cc._JavaToCPPPipe = TEST_JAVA2CPP; cc._languageID = TEST_LANGUAGE; cc._debug = TEST_DEBUG; FudgeMsg msg; ASSERT (ClientConnect_toFudgeMsg (&cc, &msg) == FUDGE_OK); FudgeMsgEnvelope env; ASSERT (FudgeMsgEnvelope_create (&env, 0, 0, 0, msg) == FUDGE_OK); fudge_byte *ptrBuffer; fudge_i32 cbBuffer; ASSERT (FudgeCodec_encodeMsg (env, &ptrBuffer, &cbBuffer) == FUDGE_OK); FudgeMsgEnvelope_release (env); FudgeMsg_release (msg); ASSERT (poPipe->Write (ptrBuffer, cbBuffer, TIMEOUT) == cbBuffer); delete ptrBuffer; } else { LOGWARN (TEXT ("Couldn't open client pipe, error ") << GetLastError ()); } }
/// Destroys a call slot, releasing any resources. CSynchronousCallSlot::~CSynchronousCallSlot () { FudgeMsg msg = m_msg.Get (); if (msg) { LOGDEBUG (TEXT ("Releasing message in deleted call slot ") << m_nIdentifier); FudgeMsg_release (msg); } }
void Run () { CSettings settings; ASSERT (settings.GetConnectionPipe ()); LOGDEBUG (TEXT ("Connecting to ") << settings.GetConnectionPipe ()); CNamedPipe *poPipe = CNamedPipe::ClientWrite (settings.GetConnectionPipe ()); ASSERT (poPipe); LOGDEBUG (TEXT ("Client connected")); ClientConnect cc; memset (&cc, 0, sizeof (cc)); cc._userName = TEST_USERNAME; cc._CPPToJavaPipe = TEST_CPP2JAVA; cc._JavaToCPPPipe = TEST_JAVA2CPP; cc._languageID = TEST_LANGUAGE; #ifdef _DEBUG cc._debug = FUDGE_TRUE; #endif /* ifdef _DEBUG */ FudgeMsg msg; ASSERT (ClientConnect_toFudgeMsg (&cc, &msg) == FUDGE_OK); FudgeMsgEnvelope env; ASSERT (FudgeMsgEnvelope_create (&env, 0, 0, 0, msg) == FUDGE_OK); fudge_byte *ptrBuffer; fudge_i32 cbBuffer; ASSERT (FudgeCodec_encodeMsg (env, &ptrBuffer, &cbBuffer) == FUDGE_OK); FudgeMsgEnvelope_release (env); FudgeMsg_release (msg); LOGDEBUG (TEXT ("Writing connection packet")); ASSERT (poPipe->Write (ptrBuffer, cbBuffer, TIMEOUT_CONNECT) == (size_t)cbBuffer); LOGDEBUG (TEXT ("Connection packet written")); delete ptrBuffer; LOGDEBUG (TEXT ("Disconnecting")); delete poPipe; }
/// Destroys the message entry. CFudgeMsgInfo::~CFudgeMsgInfo () { assert (m_nRefCount == 0); FudgeMsg_release (m_msg); if (m_pData) { free (m_pData); g_cbData -= m_cbData; } }
FudgeStatus FudgeCodec_decodeMsg ( FudgeMsgEnvelope * envelope, const fudge_byte * bytes, fudge_i32 numbytes ) { FudgeStatus status; FudgeMsgHeader header; FudgeMsg message; if ( ! envelope ) return FUDGE_NULL_POINTER; /* Get the message header and use it to create the envelope and the message */ if ( ( status = FudgeHeader_decodeMsgHeader ( &header, bytes, numbytes ) ) != FUDGE_OK ) return status; if ( numbytes < header.numbytes ) return FUDGE_OUT_OF_BYTES; if ( ( status = FudgeMsg_create ( &message ) ) != FUDGE_OK ) return status; if ( ( status = FudgeMsgEnvelope_create ( envelope, header.directives, header.schemaversion, header.taxonomy, message ) ) != FUDGE_OK ) goto release_message_and_fail; /* Envelope now has a message reference */ FudgeMsg_release ( message ); /* Advance to the end of the header */ bytes += sizeof ( FudgeMsgHeader ); numbytes -= sizeof ( FudgeMsgHeader ); /* Consume fields */ if ( ( status = FudgeCodec_decodeMsgFields ( message, bytes, numbytes ) ) != FUDGE_OK ) goto release_envelope_and_fail; return status; release_envelope_and_fail: FudgeMsgEnvelope_release ( *envelope ); release_message_and_fail: FudgeMsg_release ( message ); return status; }
void SetStash (FudgeMsg msgStash) { m_oStashMutex.Enter (); if (m_msgStash) { LOGDEBUG (TEXT ("Discarding old stash message")); FudgeMsg_release (m_msgStash); } FudgeMsg_retain (msgStash); m_msgStash = msgStash; m_oStashMutex.Leave (); }
// This must only be called from the thread that creates and connects the pipes. This then // doesn't need to acquire the pipe semaphore as the object won't be modified concurrently. // Another thread might be sending, but that's it. bool CClientService::DispatchAndRelease (FudgeMsgEnvelope env) { FudgeMsg msg = FudgeMsgEnvelope_getMessage (env); switch (FudgeMsgEnvelope_getDirectives (env)) { case MESSAGE_DIRECTIVES_CLIENT : { Operation op; if (ConnectorMessage_getOperation (msg, &op) == FUDGE_OK) { switch (op) { case HEARTBEAT : LOGDEBUG (TEXT ("Heartbeat received")); break; case POISON : // This shouldn't be sent by the Java stack LOGFATAL (TEXT ("Received poison from Java framework")); assert (0); break; case STASH : { FudgeMsg msgStash; if (ConnectorMessage_getStash (msg, &msgStash) == FUDGE_OK) { LOGDEBUG (TEXT ("Storing stash message")); m_oStateMutex.Enter (); if (m_poRunner) { m_poRunner->SetStash (msgStash); } else { LOGWARN (TEXT ("No runner thread")); } m_oStateMutex.Leave (); FudgeMsg_release (msgStash); } else { LOGWARN (TEXT ("No stash message attached")); } break; } default : LOGWARN (TEXT ("Invalid client message - operation ") << op); break; } } else { LOGWARN (TEXT ("Invalid client message")); } break; } case MESSAGE_DIRECTIVES_USER : m_oMessageReceivedMutex.Enter (); if (m_poMessageReceivedCallback) { m_poMessageReceivedCallback->OnMessageReceived (msg); } m_oMessageReceivedMutex.Leave (); break; default : LOGWARN (TEXT ("Unknown message delivery directive ") << FudgeMsgEnvelope_getDirectives (env)); break; } FudgeMsgEnvelope_release (env); return m_poPipes->IsConnected (); }
FudgeStatus FudgeCodec_decodeFieldFudgeMsg ( const fudge_byte * bytes, const fudge_i32 width, FudgeFieldData * data ) { FudgeMsg submessage; FudgeStatus status; if ( ( status = FudgeMsg_create ( &submessage ) ) != FUDGE_OK ) return status; if ( ( status = FudgeCodec_decodeMsgFields ( submessage, bytes, width ) ) != FUDGE_OK ) { FudgeMsg_release ( submessage ); return status; } data->message = submessage; return FUDGE_OK; }
FudgeStatus FudgeMsg_addFieldMsg ( FudgeMsg message, const FudgeString name, const fudge_i16 * ordinal, FudgeMsg value ) { FudgeStatus status; FudgeFieldData data; if ( ! ( message && value ) ) return FUDGE_NULL_POINTER; if ( ( status = FudgeMsg_retain ( value ) ) != FUDGE_OK ) return status; data.message = value; if ( ( status = FudgeMsg_addFieldData ( message, FUDGE_TYPE_FUDGE_MSG, name, ordinal, &data, 0 ) ) != FUDGE_OK ) { FudgeMsg_release ( value ); return status; } return FUDGE_OK; }
void FieldListNode_destroy ( FieldListNode * node ) { assert ( node ); switch ( node->field.type ) { /* Fudge message type: free the message pointer */ case FUDGE_TYPE_FUDGE_MSG: if ( node->field.data.message ) FudgeMsg_release ( node->field.data.message ); break; /* Fudge string type: free the string pointer */ case FUDGE_TYPE_STRING: if ( node->field.data.string ) FudgeString_release ( node->field.data.string ); break; /* Primitive type: nothing needs freeing */ case FUDGE_TYPE_INDICATOR: case FUDGE_TYPE_BOOLEAN: case FUDGE_TYPE_BYTE: case FUDGE_TYPE_SHORT: case FUDGE_TYPE_INT: case FUDGE_TYPE_LONG: case FUDGE_TYPE_FLOAT: case FUDGE_TYPE_DOUBLE: case FUDGE_TYPE_DATE: case FUDGE_TYPE_TIME: case FUDGE_TYPE_DATETIME: break; /* Every other type will store its data in the bytes array */ default: free ( ( fudge_byte * ) node->field.data.bytes ); break; } if ( node->field.name ) FudgeString_release ( node->field.name ); free ( node ); }
FudgeStatus FudgeMsgEnvelope_release ( FudgeMsgEnvelope envelope ) { if ( ! envelope ) return FUDGE_NULL_POINTER; if ( ! FudgeRefCount_decrementAndReturn ( envelope->refcount ) ) { /* Last reference has been released - release the message and destroy the envelope */ FudgeStatus status; if ( ( status = FudgeMsg_release ( envelope->message ) ) != FUDGE_OK ) return status; if ( ( status = FudgeRefCount_destroy ( envelope->refcount ) ) != FUDGE_OK ) return status; FUDGEMEMORY_FREE( envelope ); } return FUDGE_OK; }
/// Releases the slot back to its parent. This may be called at the same time as a PostAndRelease /// from a message receiving thread. This must not be called at the same time as GetMessage. void CSynchronousCallSlot::Release () { int nSequence = m_oSequence.IncrementAndGet () & STATE_SEQUENCE_MASK; int nState = m_oState.Get (), nAltState; FudgeMsg msg; retry: switch (nState & STATE_STATE_MASK) { case STATE_IDLE : nAltState = m_oState.CompareAndSet (STATE_IDLE | nSequence, nState); if (nAltState != nState) { LOGDEBUG (TEXT ("Retrying after state shift from ") << nState << TEXT (" to ") << nAltState); nState = nAltState; goto retry; } break; case STATE_MESSAGE_PRE : // A message is being posted; need to wait for the post to complete LOGDEBUG (TEXT ("Retrying during call to PostAndRelease on slot ") << m_nIdentifier); CThread::Yield (); nState = m_oState.Get (); goto retry; case STATE_MESSAGE_OK : // Message has been posted, but not consumed discard it msg = m_msg.GetAndSet (NULL); if (msg) { LOGDEBUG (TEXT ("Discarding message in released slot ") << m_nIdentifier); FudgeMsg_release (msg); } m_oState.Set (STATE_IDLE | nSequence); break; // STATE_WAITING cannot happen as calls to Release and GetMessage are mutually exclusive for a thread case STATE_DONE : m_oState.Set (STATE_IDLE | nSequence); break; default : LOGFATAL (TEXT ("Invalid state ") << nState); assert (0); break; } m_poOwner->Release (this); }
/// Finds an existing message entry in the map, or creates a new entry if none is found. /// The message is returned with an incremented reference count - the caller should call /// Release when finished with it (unless the reference is offloaded to R). /// /// @param[in] pData the binary encoding of the message to lock up /// @param[in] cbData the length of the binary encoding in bytes CFudgeMsgInfo *CFudgeMsgInfo::GetMessage (const void *pData, size_t cbData) { g_oMutex.Enter (); FudgeMsg msg = NULL; CFudgeMsgInfo *poMessage = NULL; void *pDataCopy = NULL; do { msg = _DecodeFudgeMsg (pData, cbData); if (!msg) { break; } TFudgeMsgMap::const_iterator itr = g_oMap.find (msg); if (itr != g_oMap.end ()) { poMessage = itr->second; poMessage->m_nRefCount++; break; } pDataCopy = malloc (cbData); if (!pDataCopy) { LOGFATAL (TEXT ("Out of memory")); break; } memcpy (pDataCopy, pData, cbData); poMessage = new CFudgeMsgInfo (msg, pDataCopy, cbData); if (!poMessage) { LOGFATAL (TEXT ("Out of memory")); break; } LOGDEBUG (TEXT ("Adding message to map (size = ") << (g_oMap.size () + 1) << TEXT (")")); g_oMap.insert (TFudgeMsgMap::value_type (msg, poMessage)); g_cbData += cbData + MESSAGE_INFO_OVERHEAD; pDataCopy = NULL; } while (false); g_oMutex.Leave (); if (msg) FudgeMsg_release (msg); if (pDataCopy) free (pDataCopy); return poMessage; }
/// Posts a message to the slot and releases a caller to GetMessage if there is one. Only one /// thread may call this at any one time. /// /// @param[in] nSequence sequence counter decoded from the message /// @param[in] msg message payload void CSynchronousCallSlot::PostAndRelease (int nSequence, FudgeMsg msg) { nSequence &= STATE_SEQUENCE_MASK; int nState = m_oState.Get (), nAltState; retry: if ((nState & STATE_SEQUENCE_MASK) != nSequence) { LOGDEBUG (TEXT ("Sequence on slot ") << m_nIdentifier << TEXT (" already advanced")); FudgeMsg_release (msg); return; } switch (nState & STATE_STATE_MASK) { case STATE_IDLE : nAltState = m_oState.CompareAndSet (STATE_MESSAGE_PRE | nSequence, nState); if (nAltState != nState) { LOGDEBUG (TEXT ("Retrying after state shift from ") << nState << TEXT (" to ") << nAltState << TEXT (" on slot ") << m_nIdentifier); nState = nAltState; goto retry; } // Now in MESSAGE_PRE state, ready to store message msg = m_msg.GetAndSet (msg); if (msg) { LOGDEBUG (TEXT ("Discarding message already in slot ") << m_nIdentifier); FudgeMsg_release (msg); } // Now advance to MESSAGE_OK state, to indicate message is in the slot m_oState.Set (STATE_MESSAGE_OK | nSequence); break; // STATE_MESSAGE_PRE cannot happen as only one thread should ever call PostAndRelease case STATE_MESSAGE_OK : LOGWARN (TEXT ("Discarding duplicate message received on slot ") << m_nIdentifier); FudgeMsg_release (msg); break; case STATE_WAITING : // Message received with another thread waiting for it nAltState = m_oState.CompareAndSet (STATE_MESSAGE_PRE | nSequence, nState); if (nAltState != nState) { LOGDEBUG (TEXT ("Retrying after state shift from ") << nState << TEXT (" to ") << nAltState << TEXT (" on slot ") << m_nIdentifier); nState = nAltState; goto retry; } // Now in MESSAGE_PRE state, ready to store message msg = m_msg.GetAndSet (msg); if (msg) { LOGDEBUG (TEXT ("Discarding message already in slot ") << m_nIdentifier); FudgeMsg_release (msg); } // Now advance to MESSAGE_OK state, to indicate message is in the slot m_oState.Set (STATE_MESSAGE_OK | nSequence); // There was another thread waiting on the semaphore LOGDEBUG (TEXT ("Signalling semaphore on slot ") << m_nIdentifier); m_sem.Signal (); break; case STATE_DONE : LOGWARN (TEXT ("Discarding late delivery of message on slot ") << m_nIdentifier); FudgeMsg_release (msg); break; default : LOGFATAL (TEXT ("Invalid state ") << nState << TEXT (" on slot ") << m_nIdentifier); assert (0); FudgeMsg_release (msg); break; } }
int main ( int argc, char * argv [ ] ) { FudgeStatus status; FudgeMsg message; FudgeMsgEnvelope envelope; AddressDetails * details [ 2 ]; fudge_i16 ordinal; fudge_byte * encoded; fudge_i32 encodedsize; /* Initialise the Fudge library */ if ( ( status = Fudge_init ( ) ) ) fatalFudgeError ( status, "Failed to initialise Fudge library" ); /* Register the AddressDetails type */ if ( ( status = FudgeRegistry_registerType ( FUDGE_TYPE_ADDRESSDETAILS, FUDGE_TYPE_PAYLOAD_BYTES, FudgeCodec_decodeFieldAddressDetails, FudgeCodec_encodeFieldAddressDetails, FudgeType_coerceAddressDetails ) ) ) fatalFudgeError ( status, "Failed to register AddressDetails type" ); /* Construct and encode two address details */ details [ 0 ] = constructAddressDetails ( Status_Past, 123, "Fake St.", "Some City", "P05 T4L" ); details [ 1 ] = constructAddressDetails ( Status_Active, 45, "Faux Road", "Some Town", "FUD 63C" ); /* Create a message and add the two details */ if ( ( status = FudgeMsg_create ( &message ) ) ) fatalFudgeError ( status, "Failed to create Fudge message" ); for ( ordinal = 0; ordinal < 2; ++ordinal ) FudgeMsg_addFieldAddressDetails ( message, 0, &ordinal, details [ ordinal ] ); /* Encode the message */ if ( ( status = FudgeMsgEnvelope_create ( &envelope, 0, 0, 0, message ) ) ) fatalFudgeError ( status, "Failed to create Fudge messag envelope" ); if ( ( status = FudgeCodec_encodeMsg ( envelope, &encoded, &encodedsize ) ) ) fatalFudgeError ( status, "Failed to encode Fudge message" ); /* Clean up source details and messge */ free ( details [ 0 ] ); free ( details [ 1 ] ); FudgeMsgEnvelope_release ( envelope ); FudgeMsg_release ( message ); /* Decode the message and release the encoded bytes array */ if ( ( status = FudgeCodec_decodeMsg ( &envelope, encoded, encodedsize ) ) ) fatalFudgeError ( status, "Failed to decode Fudge message" ); free ( encoded ); /* Retrieve, convert and display the fields */ for ( ordinal = 0; ordinal < 2; ++ordinal ) { FudgeField field; FudgeFieldData data; FudgeTypePayload payload; fudge_i32 datasize; char * ascii; if ( ( status = FudgeMsg_getFieldByOrdinal ( &field, FudgeMsgEnvelope_getMessage ( envelope ), ordinal ) ) ) fatalFudgeError ( status, "Failed to find field" ); /* Convert the field in to a string */ if ( ( status = FudgeMsg_getFieldAs ( &field, FUDGE_TYPE_STRING, &data, &payload, &datasize ) ) ) fatalFudgeError ( status, "Failed to convert field to string" ); /* This is a bit paranoid, but it's checking that the string conversion actually resulted in string payload */ if ( payload != FUDGE_TYPE_PAYLOAD_STRING ) { fprintf ( stderr, "FATAL ERROR: Retrieving field %d as a string returned a non-string!\n", ordinal ); exit ( 1 ); } FudgeString_convertToASCIIZ ( &ascii, data.string ); printf ( "Field %d: %s\n", ordinal, ascii ); free ( ascii ); FudgeString_release ( data.string ); } /* Clean up */ FudgeMsgEnvelope_release ( envelope ); return 0; }
~CRunnerThread () { LOGDEBUG (TEXT ("Runner thread destroyed")); if (m_msgStash) { FudgeMsg_release (m_msgStash); } }