RsslRet RTR_C_INLINE decodePayload(RsslDecodeIterator* dIter, RsslMsg *msg, ProviderThread* pProviderThread)
{
	RsslRet ret;
	RsslErrorInfo errorInfo;

	switch(msg->msgBase.domainType)
	{
		case RSSL_DMT_MARKET_PRICE:
			if ((ret = decodeMPUpdate(dIter, msg, pProviderThread)) != RSSL_RET_SUCCESS)
			{
				rsslSetErrorInfo(&errorInfo, RSSL_EIC_FAILURE, ret, __FILE__, __LINE__,
						(char*)"decodeMPUpdate() failed: %d(%s)", ret, rsslRetCodeToString(ret));
				return ret;
			}
			return RSSL_RET_SUCCESS;
		case RSSL_DMT_MARKET_BY_ORDER:
			if ((ret = decodeMBOUpdate(dIter, msg, pProviderThread) != RSSL_RET_SUCCESS))
			{
				rsslSetErrorInfo(&errorInfo, RSSL_EIC_FAILURE, ret, __FILE__, __LINE__,
						(char*)"decodeMBOUpdate() failed: %d(%s)", ret, rsslRetCodeToString(ret));
				return ret;
			}
			return RSSL_RET_SUCCESS;
		default:
			rsslSetErrorInfo(&errorInfo, RSSL_EIC_FAILURE, RSSL_RET_FAILURE, __FILE__, __LINE__,
					(char*)"decodePayload(): Unhandled domain type %s(%d)", 
					rsslDomainTypeToString(msg->msgBase.domainType), msg->msgBase.domainType);
			return RSSL_RET_FAILURE;
	}
}
RsslRet snapshotSessionProcessWriteReady(SnapshotSession *pSession)
{
	RsslRet ret = RSSL_RET_FAILURE;
	RsslError rsslError;

	switch(pSession->pRsslChannel->state)
	{
		case RSSL_CH_STATE_ACTIVE:
			ret = rsslFlush(pSession->pRsslChannel, &rsslError);

			/* Read values less than RSSL_RET_SUCCESS are codes to handle. */
			if (ret < RSSL_RET_SUCCESS)
			{
				/* Flush failed; close the channel. */
				printf("<%s> rsslFlush() failed: %d(%s).\n\n", pSession->name,
						ret, rsslRetCodeToString(ret));
				rsslCloseChannel(pSession->pRsslChannel, &rsslError);
				pSession->pRsslChannel = NULL;
				return ret;
			}
			else if (ret == 0)
				pSession->setWriteFd = RSSL_FALSE; /* Done flushing. */

			return RSSL_RET_SUCCESS;

		case RSSL_CH_STATE_INITIALIZING:
			return snapshotSessionInitializeChannel(pSession);

		default:
			printf("<%s> Unhandled channel state %u.\n\n", pSession->name,
					ret, rsslRetCodeToString(ret));
			exit(-1);
			return RSSL_RET_FAILURE;
	}
}
RsslRet snapshotSessionProcessChannelActive(SnapshotSession *pSession)
{
	RsslEncodeIterator encodeIter;
	RsslRDMLoginRequest loginRequest;
	RsslBuffer *pBuffer;
	RsslErrorInfo rsslErrorInfo;
	RsslError rsslError;
	RsslRet ret = RSSL_RET_FAILURE;


	/* Get a buffer from the channel for writing. */
	if (!(pBuffer = rsslGetBuffer(pSession->pRsslChannel, 1024, RSSL_FALSE, &rsslError)))
	{
		printf("<%s> rsslGetBuffer() failed while sending login request: %d (%s -- %s).\n\n",
				pSession->name,
				rsslError.rsslErrorId, rsslRetCodeToString(rsslError.rsslErrorId), rsslError.text);
		return rsslError.rsslErrorId;
	}

	/* Populate the login request with some default information. */
	if ((ret = rsslInitDefaultRDMLoginRequest(&loginRequest, LOGIN_STREAM_ID)) != RSSL_RET_SUCCESS)
	{
		printf("<%s> rsslInitDefaultRDMLoginRequest() failed: %d(%s).\n\n",
				pSession->name, ret, rsslRetCodeToString(ret));
		rsslReleaseBuffer(pBuffer, &rsslError);
		return ret;
	}

	/* Encode the login request using the RDM package encoder utility. This will
	 * translate the login request structure to an encoded message and set the proper length
	 * on the buffer. */
	rsslClearEncodeIterator(&encodeIter);
	rsslSetEncodeIteratorRWFVersion(&encodeIter, pSession->pRsslChannel->majorVersion,
			pSession->pRsslChannel->minorVersion);
	rsslSetEncodeIteratorBuffer(&encodeIter, pBuffer);
	if ((ret = rsslEncodeRDMLoginMsg(&encodeIter, (RsslRDMLoginMsg*)&loginRequest, &pBuffer->length,
					&rsslErrorInfo)) != RSSL_RET_SUCCESS)
	{
		printf("<%s> rsslEncodeRDMLoginMsg() failed: %d (%s -- %s).\n\n",
				pSession->name,
				ret, rsslRetCodeToString(ret), rsslErrorInfo.rsslError.text);
		rsslReleaseBuffer(pBuffer, &rsslError);
		return ret;
	}

	/* Write the message. */
	if ((ret = snapshotSessionWrite(pSession, pBuffer)) != RSSL_RET_SUCCESS)
		return ret;

	pSession->state = SNAPSHOT_STATE_LOGIN_REQUESTED;

	return RSSL_RET_SUCCESS;

}
RsslRet snapshotSessionConnect(SnapshotSession *pSession, RsslConnectOptions *pOpts, RsslRDMService* service)
{
	RsslError rsslError;

	pSession->pRsslChannel = rsslConnect(pOpts, &rsslError);

	if (!pSession->pRsslChannel)
	{
		printf("<%s> rsslConnect() failed: %d (%s -- %s)\n\n", pSession->name,
				rsslError.rsslErrorId, rsslRetCodeToString(rsslError.rsslErrorId), rsslError.text);
		return rsslError.rsslErrorId;
	}
	
	printf("<%s> Channel connected with FD %d.\n\n", pSession->name, pSession->pRsslChannel->socketId);

	/* If we need to initialize the channel, make our first call to rsslInitChannel() when
	 * triggered to write. */
	if (pSession->pRsslChannel->state == RSSL_CH_STATE_INITIALIZING)
		pSession->setWriteFd = RSSL_TRUE;
	else
	{
		printf("<%s> Channel is active!\n\n", pSession->name);
		pSession->setWriteFd = RSSL_FALSE;
		if (snapshotSessionProcessChannelActive(pSession) != RSSL_RET_SUCCESS)
			exit(-1);
	}

	pSession->pService = service;

	return RSSL_RET_SUCCESS;

}
static RsslRet snapshotSessionWrite(SnapshotSession *pSession, RsslBuffer *pBuffer)
{
	RsslError rsslError;
	RsslRet ret;

	RsslWriteInArgs writeInArgs;
	RsslWriteOutArgs writeOutArgs;

	/* Write the message. */
	rsslClearWriteInArgs(&writeInArgs);
	rsslClearWriteOutArgs(&writeOutArgs);
	if ((ret = rsslWriteEx(pSession->pRsslChannel, pBuffer, &writeInArgs, &writeOutArgs,
					&rsslError)) < RSSL_RET_SUCCESS)
	{
		printf("<%s> rsslWriteEx() failed: %d(%s -- %s).\n\n",
				pSession->pRsslChannel, ret, rsslRetCodeToString(ret), rsslError.text);
		rsslReleaseBuffer(pBuffer, &rsslError);
		rsslCloseChannel(pSession->pRsslChannel, &rsslError);
		pSession->pRsslChannel = NULL;
		return ret;
	}

	/* Positive values indicate that data is in the outbound queue and should be flushed. */
	if (ret > RSSL_RET_SUCCESS)
		pSession->setWriteFd = RSSL_TRUE;

	return RSSL_RET_SUCCESS;

}
/* assuming pEncFieldList RsslBuffer contains the pre-encoded payload with data and length populated */
RsslRet getPreEncodedRsslFieldListBuffer(RsslBuffer *pEncUInt)
{
	RsslRet retVal;  //used to store and check the return value from the function calls

	RsslUInt8 majorVersion = RSSL_RWF_MAJOR_VERSION;  //This should be initialized to the MAJOR version of RWF being encoded
	RsslUInt8 minorVersion = RSSL_RWF_MINOR_VERSION;  // This should be initialized to the MINOR version of RWF being encoded

	/* create and clear iterator to prepare for encoding */
	RsslEncodeIterator encodeIter;
	rsslClearEncodeIterator(&encodeIter);

	/* associate buffer and iterator, code assumes that (&encDecBuffer)->data points to 
	   sufficient memory and (&encDecBuffer)->length indicates number of bytes available in 
	   pBuffer->data */
	if ((retVal = rsslSetEncodeIteratorBuffer(&encodeIter, pEncUInt)) < RSSL_RET_SUCCESS)
	{
		printf("Error %s (%d) encountered with rsslSetEncodeIteratorBuffer().  Error Text: %s\n", 
			rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		return retVal;
	}
	/* set proper protocol version information on iterator, this can typically be obtained from 
	   the RsslChannel associated with the connection once it becomes active */
	if ((retVal = rsslSetEncodeIteratorRWFVersion(&encodeIter, majorVersion, minorVersion)) < RSSL_RET_SUCCESS)
	{
		printf("Error %s (%d) encountered with rsslSetEncodeIteratorRWFVersion().  Error Text: %s\n", 
			rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		return retVal;
	}

	if ((retVal = exampleEncodeFieldList(&encodeIter)) < RSSL_RET_SUCCESS)
	{
		printf("Error %s (%d) encountered with exampleEncodeFieldList().  Error Text: %s\n", 
			rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		return retVal;
	}

	//this is important!
	/* When encoding is complete, set the pEncUInt->length to the number of bytes Encoded */
	pEncUInt->length = rsslGetEncodedBufferLength(&encodeIter);

	return RSSL_RET_SUCCESS;
}
void processInactiveChannel(ChannelHandler *pChanHandler, ChannelInfo *pChannelInfo, RsslError *pError)
{
	ProviderThread *pProvThread = (ProviderThread*)pChanHandler->pUserSpec;
	ProviderSession *pProvSession = (ProviderSession*)pChannelInfo->pUserSpec;

	pProvThread->stats.inactiveTime = getTimeNano();

	if(pError)
		printf("Channel Closed: %s(%s)\n", rsslRetCodeToString(pError->rsslErrorId), pError->text);
	else
		printf("Channel Closed.\n");
	

	if (pProvSession)
		providerSessionDestroy(pProvThread, pProvSession);
}
char* simpleTunnelMsgHandlerCheckRequestedClassOfService(SimpleTunnelMsgHandler *pSimpleTunnelMsgHandler,
		RsslTunnelStreamRequestEvent *pEvent, RsslClassOfService *pCos)
{
	RsslErrorInfo errorInfo;

	/* 
	 * The class of service filter can be inspected to detect early if
	 * certain members of the ClassOfService are not present (and therefore
	 * have their default values).
	 *
	 * if ((pEvent->classOfServiceFilter & RDM_COS_COMMON_PROPERTIES_FLAG) == 0)
	 *	return "This provider requires the common ClassOfService filter.";
	 * else if ((pEvent->classOfServiceFilter & RDM_COS_AUTHENTICATION_FLAG) == 0)
	 *	return "This provider requires the authentication ClassOfService filter.";
	 * else if ((pEvent->classOfServiceFilter & RDM_COS_FLOW_CONTROL_FLAG) == 0)
	 *	return "This provider requires the flow control ClassOfService filter.";
	 * else if ((pEvent->classOfServiceFilter & RDM_COS_DATA_INTEGRITY_FLAG) == 0)
	 *	return "This provider requires the data integrity ClassOfService filter.";
	 */

	/* Try to decode the class of service. */
	if (rsslTunnelStreamRequestGetCos(pEvent, pCos, &errorInfo) != RSSL_RET_SUCCESS)
	{
		printf("rsslTunnelStreamRequestGetCos failed: %s(%s)\n", rsslRetCodeToString(errorInfo.rsslError.rsslErrorId), &errorInfo.rsslError.text);
		return (char*)"Failed to decode class of service.";
	}

	/* Check if it matches what we require. */

	if (pCos->common.protocolType != RSSL_RWF_PROTOCOL_TYPE)
		return (char*)"This provider doesn't support this protocol type.";

	if (pCos->common.protocolMajorVersion != RSSL_RWF_MAJOR_VERSION)
		return (char*)"This provider doesn't support this wire format major version.";

	if (pCos->authentication.type != RDM_COS_AU_NOT_REQUIRED
			&& pCos->authentication.type != RDM_COS_AU_OMM_LOGIN)
		return (char*)"This provider doesn't support this type of authentication.";

	if (pCos->flowControl.type != RDM_COS_FC_BIDIRECTIONAL)
		return (char*)"This provider requires bidirectional flow control.";

	if (pCos->guarantee.type != RDM_COS_GU_NONE)
		return (char*)"This provider does not support guaranteed streams.";

	return NULL;
}
/*
 * Closes channel, cleans up and exits the application.
 * upaChannel - The channel to be closed
 * code - if exit due to errors/exceptions
 */
void closeChannelCleanUpAndExit(RsslChannel* upaChannel, int code)
{
	RsslRet	retval = 0;
	RsslError error;
	RsslBuffer* msgBuf = 0;

	/*********************************************************
	 * Client/NIProv Application Liefcycle Major Step 5:
	 * Close connection using rsslCloseChannel (OS connection release handshake)
	 * rsslCloseChannel closes the client based RsslChannel. This will release any pool based resources 
	 * back to their respective pools, close the connection, and perform any additional necessary cleanup.
	 * When shutting down the RSSL Transport, the application should release all unwritten pool buffers. 
	 * Calling rsslCloseChannel terminates the connection to the ADH.
	 *********************************************************/

	if ((retval = rsslCloseChannel(upaChannel, &error)) < RSSL_RET_SUCCESS)
	{
		printf("Error %s (%d) (errno: %d) encountered with rsslCloseChannel. Error Text: %s\n", 		
			rsslRetCodeToString(error.rsslErrorId), error.rsslErrorId, error.sysError, error.text);
	}

	/*********************************************************
	 * Client/NIProv Application Liefcycle Major Step 6:
	 * Uninitialize UPA Transport using rsslUninitialize
	 * The last UPA Transport function that an application should call. This uninitializes internal data 
	 * structures and deletes any allocated memory.
	 *********************************************************/
	
	/* All UPA Transport use is complete, must uninitialize. 
	 * The uninitialization process allows for any heap allocated memory to be cleaned up properly. 
	 */
	rsslUninitialize();

	/* For applications that do not exit due to errors/exceptions such as:
	 * Exits the application if the run-time has expired. 
	 */
	if (code == RSSL_RET_SUCCESS)
		printf("\nUPA NI Provider Training application successfully ended.\n");

	/* End application */
	exit(code);
}
RsslRet snapshotSessionInitializeChannel(SnapshotSession *pSession)
{
	RsslInProgInfo inProg;
	RsslRet ret;
	RsslError rsslError;

	ret = rsslInitChannel(pSession->pRsslChannel, &inProg, &rsslError);

	switch(ret)
	{
		case RSSL_RET_SUCCESS: 
			/* Success indicates that initialization is complete. */
			pSession->setWriteFd = RSSL_FALSE;
			printf("<%s> Channel is active!\n\n", pSession->name);
			if ((ret = snapshotSessionProcessChannelActive(pSession)) != RSSL_RET_SUCCESS)
				return ret;
			return RSSL_RET_SUCCESS;

		case RSSL_RET_CHAN_INIT_IN_PROGRESS:

			if (inProg.flags & RSSL_IP_FD_CHANGE)
			{
				/* Indicates that the file descriptor for this channel changed. */
				printf("<%s> Channel FD changed while initializing (from %d to %d)\n\n", pSession->name,
						inProg.oldSocket, inProg.newSocket);

				/* This normally means that the channel was reconnected while initializing,
				 * so trigger ourselves to call rsslInitChannel on write notification
				 * again.  */
				pSession->setWriteFd = RSSL_TRUE;
			}
			else
				pSession->setWriteFd = RSSL_FALSE;

			return RSSL_RET_SUCCESS;

		default:
			printf("<%s> rsslInitChannel() failed: %d(%s).\n\n",
					pSession->name, ret, rsslRetCodeToString(ret));
			return ret;
	}
}
static void simpleTunnelMsgHandlerSendMessage(SimpleTunnelMsgHandler *pSimpleTunnelMsgHandler)
{
	RsslTunnelStream *pTunnelStream = pSimpleTunnelMsgHandler->tunnelStreamHandler.pTunnelStream;
	RsslReactorChannel *pReactorChannel = pTunnelStream->pReactorChannel;

	RsslTunnelStreamSubmitOptions submitOpts;
	RsslTunnelStreamGetBufferOptions bufferOpts;
	RsslEncodeIterator eIter;
	RsslBuffer *pBuffer;
	RsslRet ret, ret2;
	RsslErrorInfo errorInfo;

	rsslClearTunnelStreamGetBufferOptions(&bufferOpts);
	bufferOpts.size = 1024;
	if ((pBuffer = rsslTunnelStreamGetBuffer(pTunnelStream, &bufferOpts, &errorInfo)) == NULL)
	{
		printf("rsslTunnelStreamGetBuffer failed: %s(%s)\n", rsslRetCodeToString(errorInfo.rsslError.rsslErrorId), &errorInfo.rsslError.text);
		return;
	}

	rsslClearEncodeIterator(&eIter);
	rsslSetEncodeIteratorRWFVersion(&eIter, pTunnelStream->classOfService.common.protocolMajorVersion,
			pTunnelStream->classOfService.common.protocolMinorVersion);
	rsslSetEncodeIteratorBuffer(&eIter, pBuffer);

	/* Write text as the data body. */
	pBuffer->length = snprintf(pBuffer->data, pBuffer->length, "TunnelStream Message: %d", pSimpleTunnelMsgHandler->msgCount + 1);

	/* Message encoding complete; submit it. */
	rsslClearTunnelStreamSubmitOptions(&submitOpts);
	submitOpts.containerType = RSSL_DT_OPAQUE;
	if ((ret = rsslTunnelStreamSubmit(pTunnelStream, pBuffer, &submitOpts, &errorInfo)) != RSSL_RET_SUCCESS)
	{
		printf("rsslTunnelStreamSubmit(): Failed <%s>\n", errorInfo.rsslError.text);
		if ((ret2 = rsslTunnelStreamReleaseBuffer(pBuffer, &errorInfo)) != RSSL_RET_SUCCESS)
			printf("rsslTunnelStreamReleaseBuffer(): Failed <%d:%s>\n", ret2, errorInfo.rsslError.text);
		return;
	}

	++pSimpleTunnelMsgHandler->msgCount;
}
void queueMsgHandlerProcessTunnelOpened(RsslTunnelStream *pTunnelStream)
{
	TunnelStreamHandler *pTunnelHandler = (TunnelStreamHandler*)pTunnelStream->userSpecPtr;
	QueueMsgHandler *pQueueMsgHandler = (QueueMsgHandler*)pTunnelStream->userSpecPtr;
	RsslTunnelStreamSubmitMsgOptions tunnelStreamSubmitOptions;
	RsslRDMQueueRequest queueRequest;
	RsslRet ret;
	RsslErrorInfo errorInfo;

	pQueueMsgHandler->identifier = 0;
	pQueueMsgHandler->isQueueStreamOpen = RSSL_FALSE;

	// open a queue message sub-stream for this tunnel stream
	rsslClearRDMQueueRequest(&queueRequest);
	queueRequest.rdmMsgBase.streamId = QUEUE_MSG_STREAM_ID;
	queueRequest.rdmMsgBase.domainType = QUEUE_MSG_DOMAIN;
	queueRequest.sourceName =  pQueueMsgHandler->sourceName;

	rsslClearTunnelStreamSubmitMsgOptions(&tunnelStreamSubmitOptions);
	tunnelStreamSubmitOptions.pRDMMsg = (RsslRDMMsg *)&queueRequest;
	if ((ret = rsslTunnelStreamSubmitMsg(pTunnelStream, &tunnelStreamSubmitOptions, &errorInfo)) != RSSL_RET_SUCCESS)
		printf("rsslTunnelStreamSubmitMsg failed: %s(%s)\n", rsslRetCodeToString(ret), errorInfo.rsslError.text);

}
void processInactiveChannel(ChannelHandler *pChanHandler, ChannelInfo *pChannelInfo, RsslError *pError)
{
	ProviderThread *pProviderThread = (ProviderThread*)pChanHandler->pUserSpec;
	ProviderSession *pProvSession = (ProviderSession*)pChannelInfo->pUserSpec;

	/* If the channel was active, then the test was started so we won't attempt to reconnect,
	 * so stop the test. */
	if (!signal_shutdown && pProvSession->timeActivated)
	{
		signal_shutdown = RSSL_TRUE;
		testFailed = RSSL_TRUE;
	}

	if(pError)
		printf("Channel Closed: %s(%s)\n", rsslRetCodeToString(pError->rsslErrorId), pError->text);
	else
		printf("Channel Closed.\n");

	if (pProvSession)
	{
		providerSessionDestroy(pProviderThread, pProvSession);
		pChannelInfo->pUserSpec = NULL;
	}
}
RsslRet snapshotSessionRequestItems(SnapshotSession *pSession)
{
	RsslUInt32 i;
	RsslEncodeIterator encodeIter;
	RsslRequestMsg requestMsg;
	RsslBuffer *pBuffer;
	RsslError rsslError;
	RsslRet ret;

	for (i = 0; i < itemList.itemCount; ++i)
	{
		Item *pItem = &itemList.items[i];

		if (!(pBuffer = rsslGetBuffer(pSession->pRsslChannel, 128, RSSL_FALSE, &rsslError)))
		{
			printf("<%s> rsslGetBuffer() failed while sending item request: %d (%s -- %s).\n\n",
					pSession->name,
					rsslError.rsslErrorId, rsslRetCodeToString(rsslError.rsslErrorId), rsslError.text);
			return ret;
		}

		rsslClearRequestMsg(&requestMsg);
		requestMsg.flags = RSSL_RQMF_HAS_QOS;
		requestMsg.msgBase.streamId = pItem->snapshotServerStreamId;
		requestMsg.msgBase.domainType = pItem->domainType;
		requestMsg.msgBase.containerType = RSSL_DT_NO_DATA;
		requestMsg.qos.rate = RSSL_QOS_RATE_TICK_BY_TICK;
		requestMsg.qos.timeliness = RSSL_QOS_TIME_REALTIME;

		/* This system uses the real-time feed's stream ID as the name. */
		requestMsg.msgBase.msgKey.flags = RSSL_MKF_HAS_SERVICE_ID | RSSL_MKF_HAS_IDENTIFIER;
		requestMsg.msgBase.msgKey.identifier = pItem->feedStreamId;
		requestMsg.msgBase.msgKey.serviceId = exampleConfig.serviceId;

		rsslClearEncodeIterator(&encodeIter);
		rsslSetEncodeIteratorRWFVersion(&encodeIter, pSession->pRsslChannel->majorVersion,
				pSession->pRsslChannel->minorVersion);
		rsslSetEncodeIteratorBuffer(&encodeIter, pBuffer);
		if ((ret = rsslEncodeMsg(&encodeIter, (RsslMsg*)&requestMsg)) != RSSL_RET_SUCCESS)
		{
			printf("<%s> rsslEncodeMsg() failed while sending item request: %d (%s).\n\n",
					pSession->name,
					ret, rsslRetCodeToString(ret));
			rsslReleaseBuffer(pBuffer, &rsslError);
			return ret;
		}

		pBuffer->length = rsslGetEncodedBufferLength(&encodeIter);

		/* Write the message. */
		if ((ret = snapshotSessionWrite(pSession, pBuffer)) != RSSL_RET_SUCCESS)
			return ret;

		printf("<%s> Sent request for item %s, %s on stream %d.\n\n",
				pSession->name, pItem->symbolName,
				rsslDomainTypeToString(pItem->domainType), pItem->snapshotServerStreamId);

	}

	return RSSL_RET_SUCCESS;
}
static RsslRet snapshotSessionProcessMessage(SnapshotSession *pSession, RsslBuffer *pBuffer)
{
	RsslDecodeIterator decodeIter;
	RsslRet ret;
	RsslErrorInfo rsslErrorInfo;
	RsslMsg rsslMsg;
	char tempMem[1024];
	RsslBuffer tempBuffer;
	Item *pItem;

	printf("<%s> Received message:\n", pSession->name);

	/* Decode the message header. */
	rsslClearDecodeIterator(&decodeIter);
	rsslSetDecodeIteratorRWFVersion(&decodeIter, pSession->pRsslChannel->majorVersion,
			pSession->pRsslChannel->minorVersion);
	rsslSetDecodeIteratorBuffer(&decodeIter, pBuffer);
	if ((ret = rsslDecodeMsg(&decodeIter, &rsslMsg)) != RSSL_RET_SUCCESS)
	{
		printf("<%s> rsslDecodeMsg() failed: %d(%s).\n\n", 
				pSession->name, ret, rsslRetCodeToString(ret));
		return ret;
	}

	switch(rsslMsg.msgBase.domainType)
	{
		case RSSL_DMT_LOGIN:
		{
			/* Decode the message using the RDM package decoder utility. */
			RsslRDMLoginMsg loginMsg;

			tempBuffer.data = tempMem;
			tempBuffer.length = sizeof(tempMem);

			if ((ret = rsslDecodeRDMLoginMsg(&decodeIter, &rsslMsg, &loginMsg, &tempBuffer, 
							&rsslErrorInfo)) != RSSL_RET_SUCCESS)
			{
				printf(	"<%s> rsslDecodeRDMLoginMsg() failed: %d (%s -- %s)\n"
						"  at %s.\n\n",
						pSession->name,
						ret, rsslRetCodeToString(ret), rsslErrorInfo.rsslError.text,
						rsslErrorInfo.errorLocation);
				return ret;
			}

			switch(loginMsg.rdmMsgBase.rdmMsgType)
			{
				case RDM_LG_MT_REFRESH:
					printf("<%s> Received login refresh.\n\n",
							pSession->name,
							ret, rsslRetCodeToString(ret), rsslErrorInfo.rsslError.text);

					if (pSession->state == SNAPSHOT_STATE_LOGIN_REQUESTED)
					{
						if (snapshotSessionSendSymbolListRequest(pSession) != RSSL_RET_SUCCESS)
							return ret;
					}

					break;

				default:
					printf("<%s> Received unhandled RDM Login Message Type %d.\n\n",
							pSession->name, loginMsg.rdmMsgBase.rdmMsgType);
					return RSSL_RET_FAILURE;
			}
			return RSSL_RET_SUCCESS;
		}

		case RSSL_DMT_SYMBOL_LIST:
		{
			processSymbolListResponse(pSession, &rsslMsg, &decodeIter);

			if (rsslMsg.refreshMsg.flags & RSSL_RFMF_REFRESH_COMPLETE)
			{
				pSession->state = SNAPSHOT_STATE_SYMBOL_LIST_RECEIVED;
			}
		}
		break;

		default:
		{
			if ((pItem = itemListGetItemBySnapStreamID(&itemList, rsslMsg.msgBase.streamId, rsslMsg.msgBase.domainType))
					== NULL)
			{
				printf("<%s> Received unhandled message with snapshot stream ID %d, and domain %d(%s).\n\n",
						pSession->name,
						rsslMsg.msgBase.streamId,
						rsslMsg.msgBase.domainType,
						rsslDomainTypeToString(rsslMsg.msgBase.domainType));

				return RSSL_RET_SUCCESS;
			}

			return itemProcessMsg(pItem, &decodeIter, &rsslMsg, RSSL_TRUE);
		}

	}

	return RSSL_RET_SUCCESS;
}
RsslRet snapshotSessionProcessReadReady(SnapshotSession *pSession)
{
	RsslRet readRet;
	RsslRet ret = RSSL_RET_FAILURE;
	RsslError rsslError;


	RsslBuffer *pBuffer;
	RsslReadInArgs readInArgs;
	RsslReadOutArgs readOutArgs;

	switch(pSession->pRsslChannel->state)
	{
		case RSSL_CH_STATE_ACTIVE:

			rsslClearReadInArgs(&readInArgs);
			rsslClearReadOutArgs(&readOutArgs);

			pBuffer = rsslReadEx(pSession->pRsslChannel, &readInArgs, &readOutArgs, &readRet, 
					&rsslError);

			if (pBuffer)
			{
				if ((ret = snapshotSessionProcessMessage(pSession, pBuffer)) != RSSL_RET_SUCCESS)
					return ret;
			}

			if (readRet >= RSSL_RET_SUCCESS)
				return readRet;

			/* Read values less than RSSL_RET_SUCCESS are codes to handle. */
			switch (readRet)
			{
				case RSSL_RET_READ_FD_CHANGE:
					/* Channel's file descriptor was changed. */
					printf("<%s> Channel FD changed while reading (from %d to %d).\n\n",
							pSession->name, pSession->pRsslChannel->oldSocketId,
							pSession->pRsslChannel->socketId);
					return RSSL_RET_SUCCESS;

				case RSSL_RET_READ_PING:
					/* Received a ping message. */
					printf("<%s> Received ping.\n\n", pSession->name);
					return RSSL_RET_SUCCESS;

				case RSSL_RET_READ_WOULD_BLOCK:
					/* Nothing to read. */
					return RSSL_RET_SUCCESS;

				case RSSL_RET_FAILURE:
				default:
					/* Channel failed or unhandled code; close the channel. */
					printf("<%s> rsslReadEx() failed: %d(%s -- %s).\n\n", pSession->name,
							readRet, rsslRetCodeToString(readRet), rsslError.text);
					rsslCloseChannel(pSession->pRsslChannel, &rsslError);
					pSession->pRsslChannel = NULL;
					return readRet;
			}

		case RSSL_CH_STATE_INITIALIZING:
			return snapshotSessionInitializeChannel(pSession);

		default:
			printf("<%s> Unhandled channel state %u.\n\n", pSession->name,
					ret, rsslRetCodeToString(ret));
			exit(-1);
			return RSSL_RET_FAILURE;


	}

}
/* this function will encode a basic element list with several primitives embedded in it */
RsslRet exampleDecodeElementList(RsslDecodeIterator *decIter)
{
	/* create and initialize element list structure */
	RsslElementList elementList = RSSL_INIT_ELEMENT_LIST;

	/* create a single RsslElementEntry and reuse for each entry */
	RsslElementEntry elemEntry = RSSL_INIT_ELEMENT_ENTRY;

	/* used to store and check return codes */
	RsslRet retVal;

	/* structures for decoding various data types */
	RsslTime rsslTime;
	RsslReal rsslReal;
	RsslInt rsslInt;
	RsslUInt rsslUInt;
	
	/* decode into the element list structure */
	if ((retVal = rsslDecodeElementList(decIter, &elementList, NULL)) < RSSL_RET_SUCCESS)
	{
		/* decoding failure tends to be unrecoverable */
		printf("Error %s (%d) encountered with rsslDecodeElementList().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
		return RSSL_RET_FAILURE;
	}
	printf("\tElementList Header Decoded\n");
	
	/* decode each element entry */
	while ((retVal = rsslDecodeElementEntry(decIter, &elemEntry)) != RSSL_RET_END_OF_CONTAINER)
	{
		if (retVal < RSSL_RET_SUCCESS)
		{
			/* decoding failure tends to be unrecoverable */
			printf("Error %s (%d) encountered with rsslDecodeElementEntry().  Error Text: %s\n", 
					rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
			return RSSL_RET_FAILURE;
		}

		/* Continue decoding field entries. */

		printf("\tDecoding Element Entry (name: %.*s) \n", elemEntry.name.length, elemEntry.name.data);

		/* use elemEntry.dataType to call correct primitive decode function */
		switch (elemEntry.dataType)
		{	
			case RSSL_DT_REAL:
				if ((retVal = rsslDecodeReal(decIter, &rsslReal)) < RSSL_RET_SUCCESS)
				{
					printf("Error %s (%d) encountered with rsslDecodeReal().  Error Text: %s\n", 
							rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
					return RSSL_RET_FAILURE;
				}
				if (rsslReal.isBlank)
					printf("\t\tDecoded RsslReal: Blank\n");
				else
					printf("\t\tRsslReal Decoded: hint: %d  value: " RTR_LLD "\n", rsslReal.hint, rsslReal.value);
				break;
			
			case RSSL_DT_TIME:
				if ((retVal = rsslDecodeTime(decIter, &rsslTime)) < RSSL_RET_SUCCESS)
				{
					printf("Error %s (%d) encountered with rsslDecodeTime().  Error Text: %s\n", 
							rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
					return RSSL_RET_FAILURE;
				}
				printf("\t\tRsslTime Decoded: %d:%d:%d\n", rsslTime.hour, rsslTime.minute, rsslTime.second);
				break;

			case RSSL_DT_INT:
				if ((retVal = rsslDecodeInt(decIter, &rsslInt)) < RSSL_RET_SUCCESS)
				{
					printf("Error %s (%d) encountered with rsslDecodeInt().  Error Text: %s\n", 
							rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
					return RSSL_RET_FAILURE;
				}
				printf("\t\tRsslInt Decoded: " RTR_LLD "\n", rsslInt);
				break;
			
			case RSSL_DT_UINT:
				if ((retVal = rsslDecodeUInt(decIter, &rsslUInt)) < RSSL_RET_SUCCESS)
				{
					printf("Error %s (%d) encountered with rsslDecodeUInt().  Error Text: %s\n", 
							rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
					return RSSL_RET_FAILURE;
				}
				printf("\t\tRsslUInt Decoded: " RTR_LLU "\n", rsslUInt);
				break;
			
			default:
				printf("Error: unexpected datatype(%d) found in elementList\n", elemEntry.dataType);
				break;
		}
	}

	printf("\tElementList Decoding Complete\n");
	return RSSL_RET_SUCCESS;
}
RSSL_THREAD_DECLARE(runNIProvConnection, pArg)
{

	ProviderThread *pProviderThread = (ProviderThread*)pArg;
	RsslError error;

	TimeValue nextTickTime;
	RsslInt32 currentTicks = 0;
	RsslConnectOptions copts;

	if (pProviderThread->cpuId >= 0)
	{
		if (bindThread(pProviderThread->cpuId) != RSSL_RET_SUCCESS)
		{
			printf("Error: Failed to bind thread to core %d.\n", pProviderThread->cpuId);
			exit(-1);
		}
	}

	/* Configure connection options. */
	rsslClearConnectOpts(&copts);
	copts.guaranteedOutputBuffers = niProvPerfConfig.guaranteedOutputBuffers;
	copts.majorVersion = RSSL_RWF_MAJOR_VERSION;
	copts.minorVersion = RSSL_RWF_MINOR_VERSION;
	copts.protocolType = RSSL_RWF_PROTOCOL_TYPE;
	copts.sysSendBufSize = niProvPerfConfig.sendBufSize;
	copts.sysRecvBufSize = niProvPerfConfig.recvBufSize;
	if (niProvPerfConfig.sAddr || niProvPerfConfig.rAddr)
	{
		if (niProvPerfConfig.connectionType != RSSL_CONN_TYPE_RELIABLE_MCAST)
		{
			printf("Error: Attempting non-multicast segmented connection.\n");
			exit(-1);
		}

		copts.connectionInfo.segmented.recvAddress = niProvPerfConfig.recvAddr;
		copts.connectionInfo.segmented.recvServiceName = niProvPerfConfig.recvPort;
		copts.connectionInfo.segmented.sendAddress = niProvPerfConfig.sendAddr;
		copts.connectionInfo.segmented.sendServiceName = niProvPerfConfig.sendPort;
		copts.connectionInfo.segmented.interfaceName = niProvPerfConfig.interfaceName;
		copts.connectionInfo.unified.unicastServiceName = niProvPerfConfig.unicastPort;		
		copts.connectionType = RSSL_CONN_TYPE_RELIABLE_MCAST;
	}
	else
	{
		copts.connectionInfo.unified.address = niProvPerfConfig.hostName;
		copts.connectionInfo.unified.serviceName = niProvPerfConfig.portNo;
		copts.connectionInfo.unified.interfaceName = niProvPerfConfig.interfaceName;
		copts.tcp_nodelay = niProvPerfConfig.tcpNoDelay;
		copts.connectionType = RSSL_CONN_TYPE_SOCKET;
	}

	/* Setup connection. */

	do
	{
		ProviderSession *pProvSession;
		RsslChannel *pChannel;
		RsslRet ret;

		if (niProvPerfConfig.sAddr || niProvPerfConfig.rAddr)
			printf("\nAttempting segmented connect to server %s:%s  %s:%s unicastPort %s...\n", 
					niProvPerfConfig.sendAddr, niProvPerfConfig.sendPort, niProvPerfConfig.recvAddr, niProvPerfConfig.recvPort, niProvPerfConfig.unicastPort);
		else
			printf("\nAttempting unified connect to server %s:%s...\n", 
					niProvPerfConfig.hostName, niProvPerfConfig.portNo) ;

		if (!(pChannel = rsslConnect(&copts, &error)))
		{
			printf("rsslConnect() failed: %s(%s)\n", rsslRetCodeToString(error.rsslErrorId),
					error.text);
			SLEEP(1);
			continue;
		}

		if (!(pProvSession = providerSessionCreate(pProviderThread, pChannel)))
		{
			printf("providerSessionInit() failed\n");
			exit(-1);
		}
		
		do
		{
			ret = channelHandlerWaitForChannelInit(&pProviderThread->channelHandler, 
					pProvSession->pChannelInfo, 100000);
		} while (!signal_shutdown && ret == RSSL_RET_CHAN_INIT_IN_PROGRESS);

		if (ret < RSSL_RET_SUCCESS)
		{
			SLEEP(1);
			continue;
		}
		else
			break; /* Successful initialization. */

	} while (!signal_shutdown);



	nextTickTime = getTimeNano() + nsecPerTick;

	/* this is the main loop */
	while(rtrLikely(!signal_shutdown))
	{
		for (currentTicks = 0; currentTicks < providerThreadConfig.ticksPerSec; ++currentTicks)
		{
			providerThreadRead(pProviderThread, nextTickTime);

			nextTickTime += nsecPerTick;

			providerThreadSendMsgBurst(pProviderThread, nextTickTime);
		}

		providerThreadCheckPings(pProviderThread);

	}

	return RSSL_THREAD_RETURN();
}
/*
 * Initialization for cache use
 */
static void initializeCache(RsslBool cacheOption)
{
	RsslRet ret;
	if (cacheOption)
	{
		if ((ret = rsslPayloadCacheInitialize()) != RSSL_RET_SUCCESS)
		{
			printf("rsslPayloadCacheInitialize() failed: %d (%s). Cache will be disabled.", ret, rsslRetCodeToString(ret));
			cacheInfo.useCache = RSSL_FALSE;
			return;
		}

		cacheInfo.useCache = RSSL_TRUE;
		cacheInfo.cacheOptions.maxItems = 10000;
		rsslCacheErrorClear(&cacheInfo.cacheErrorInfo);
		snprintf(cacheInfo.cacheDictionaryKey, sizeof(cacheInfo.cacheDictionaryKey), "cacheDictionary%d", 1);

		cacheInfo.cacheHandle = rsslPayloadCacheCreate(&cacheInfo.cacheOptions,
				&cacheInfo.cacheErrorInfo);
		if (cacheInfo.cacheHandle == 0)
		{
			printf("Error: Failed to create cache.\n\tError (%d): %s\n",
					cacheInfo.cacheErrorInfo.rsslErrorId, cacheInfo.cacheErrorInfo.text);
			cacheInfo.useCache = RSSL_FALSE;
		}

		cacheInfo.cursorHandle = rsslPayloadCursorCreate();
		if (cacheInfo.cursorHandle == 0)
		{
			printf("Error: Failed to create cache cursor.\n");
			cacheInfo.useCache = RSSL_FALSE;
		}
	}
	else
	{
		cacheInfo.useCache = RSSL_FALSE;
		cacheInfo.cacheHandle = 0;
		cacheInfo.cursorHandle = 0;
	}
}
Exemple #20
0
/* decodes the simple map that is encoded above */
RsslRet exampleDecodeMap(RsslDecodeIterator *decIter)
{
	/* used to store and check return codes */
	RsslRet retVal;

	/* create our map to decode into */
	RsslMap rsslMap = RSSL_INIT_MAP;

	/* decode contents into the map structure */
	/* decode our map header */
	if ((retVal = rsslDecodeMap(decIter, &rsslMap)) >= RSSL_RET_SUCCESS)
	{
		/* create primitive value to have key decoded into and a single map entry to reuse */
		RsslUInt rsslUInt = 0;
		RsslMapEntry mapEntry = RSSL_INIT_MAP_ENTRY;

		printf("\tRsslMap Header Decoded: TotalCountHint: %d\n", rsslMap.totalCountHint);

		/* if summary data is present, invoking decoder for that type (instead of DecodeEntry)
		indicates to UPA that user wants to decode summary data */
		if (rsslMap.flags & RSSL_MPF_HAS_SUMMARY_DATA)
		{
			/* summary data is present.  Its type should be that of rsslMap.containerType */

			printf("\tDecoding Summary Data\n");

			/* Continue decoding field entries.  See example in Section 11.3.1 */
			/* decode the field list */
			if ((retVal = exampleDecodeFieldList(decIter)) < RSSL_RET_SUCCESS)
			{
				printf("<%s:%d> Error decoding nested field list.\n", __FILE__, __LINE__);
				printf("Error %s (%d) encountered with exampleEncodeFieldList().  Error Text: %s\n", 
					rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
				return retVal;
			}

			printf("\tSummary Data Decoding Complete\n");
		}

		/* decode each map entry, passing in pointer to keyPrimitiveType decodes mapEntry key as well  */
		while ((retVal = rsslDecodeMapEntry(decIter, &mapEntry, &rsslUInt)) != RSSL_RET_END_OF_CONTAINER)
		{
			if (retVal < RSSL_RET_SUCCESS)
			{
				/* decoding failure tends to be unrecoverable */
				printf("Error %s (%d) encountered with rsslDecodeMapEntry().  Error Text: %s\n", 
					rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
				return retVal;
			}
			else
			{
				/* Continue decoding field entries. */

				printf("\tDecoding Map Entry (key: " RTR_LLU ")\n", rsslUInt);

				/* Delete actions have no payload and we need to avoid decoding FieldList for this situation */
				if (mapEntry.action != RSSL_MPEA_DELETE_ENTRY)
				{
					if ((retVal = exampleDecodeFieldList(decIter)) < RSSL_RET_SUCCESS)
					{
						printf("<%s:%d> Error decoding nested field list.\n", __FILE__, __LINE__);
						printf("Error %s (%d) encountered with exampleEncodeFieldList().  Error Text: %s\n", 
							rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
						return retVal;
					}
				}
				else
				{
					printf("\tMap Entry (key: " RTR_LLU ") delete actions have no payload to decode\n", rsslUInt);
				}

				printf("\tMap Entry (key: " RTR_LLU ") Decoding Complete\n", rsslUInt);
			}
		}
	}
	else
	{
		/* decoding failure tends to be unrecoverable */
		printf("Error %s (%d) encountered with rsslDecodeMap().  Error Text: %s\n", 
			rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
		return retVal;
	}

	printf("\tRsslMap Decoding Complete\n");

	return RSSL_RET_SUCCESS;
}
static RsslRet processSymbolListResponse(SnapshotSession* pSession, RsslMsg* msg, RsslDecodeIterator* dIter)
{
	RsslRet ret = 0;

	RsslMsgKey* key = 0;
	RsslMap rsslMap;
	RsslMapEntry mapEntry;
	RsslVector rsslVector;
	RsslVectorEntry vectorEntry;
	char tempData[1024];
	char mapKeyData[32];
	RsslBuffer tempBuffer;
	RsslBuffer fidBufferValue;
	RsslLocalFieldSetDefDb fieldSetDefDb;
	RsslLocalElementSetDefDb elemSetDefDb;
	RsslElementList elemList;
	RsslElementEntry elemEntry;
	RsslFieldEntry fieldEntry;
	RsslFieldList fieldList;
	RsslBuffer stringBuf;
	char data[24];

	tempBuffer.data = tempData;
	tempBuffer.length = 1024;

	switch(msg->msgBase.msgClass)
	{
	case RSSL_MC_REFRESH:

		printf("\n<%s> Received symbol list refresh.\n\n", pSession->name);
	case RSSL_MC_UPDATE:

		/* decode symbol list response */
		/* get key*/
		key = (RsslMsgKey *)rsslGetMsgKey(msg);

		if(msg->msgBase.msgClass == RSSL_MC_REFRESH)
		{
			rsslStateToString(&tempBuffer, &msg->refreshMsg.state);
			printf("%.*s\n", tempBuffer.length, tempBuffer.data);
		}

		rsslClearMap(&rsslMap);

		if ((ret = rsslDecodeMap(dIter, &rsslMap)) != RSSL_RET_SUCCESS)
		{
			printf("<%s> rsslDecodeMap() failed with return code: %d\n", pSession->name, ret);
			return RSSL_RET_FAILURE;
		}

		if (rsslMap.flags & RSSL_MPF_HAS_SET_DEFS)
		{
			/* must ensure it is the correct type - if map contents are element list, this is a field set definition db */
			if (rsslMap.containerType == RSSL_DT_FIELD_LIST)
			{
				rsslClearLocalFieldSetDefDb(&fieldSetDefDb);
				if ((ret = rsslDecodeLocalFieldSetDefDb(dIter, &fieldSetDefDb)) < RSSL_RET_SUCCESS)
				{
					/* decoding failures tend to be unrecoverable */
					printf("<%s> Error %s (%d) encountered with rsslDecodeLocalElementSetDefDb().  Error Text: %s\n",
						pSession->name,
						rsslRetCodeToString(ret), ret, rsslRetCodeInfo(ret));
					return ret;
				}
			}
		}

		/* decode the map */
		while ((ret = rsslDecodeMapEntry(dIter, &mapEntry, mapKeyData)) != RSSL_RET_END_OF_CONTAINER)
		{
			if(ret != RSSL_RET_SUCCESS)
			{
				printf("<%s> rsslDecodeMapEntry() failed with return code: %d\n", pSession->name, ret);
				return RSSL_RET_FAILURE;
			}

			stringBuf.data = data;
			stringBuf.length = 24;
			rsslPrimitiveToString(&mapKeyData,rsslMap.keyPrimitiveType,&stringBuf);

			printf("\nID: %s, ", stringBuf.data);
			pSession->symbolListEntry[SymbolListCounter] = (SymbolListEntry*)malloc(sizeof(SymbolListEntry));
			pSession->symbolListEntry[SymbolListCounter]->id = atoi(stringBuf.data);

			if ((ret = rsslDecodeFieldList(dIter, &fieldList, &fieldSetDefDb)) != RSSL_RET_SUCCESS)
			{
				printf("<%s> rsslDecodeMap() failed with return code: %d\n", pSession->name, ret);
				return RSSL_RET_FAILURE;
			}


			/* The following fields are needed to uniquely identify a symbol on the realtime and gap fill streams:
			FID		Name						Type
			3422	Provider Symbol				RMTES_STRING
			8746	Provider Symbol 2			RMTES_STRING
			32639	Multicast channel(RT)		Vector of Element Lists
			32640	Multicast Channel(Gapfill)	Vector of Element Lists
			*/


			while ((ret = rsslDecodeFieldEntry(dIter, &fieldEntry)) != RSSL_RET_END_OF_CONTAINER)
			{
				if (ret != RSSL_RET_SUCCESS)
				{
					printf("<%s> rsslDecodeFieldEntry() failed with return code: %d\n", pSession->name, ret);
					return RSSL_RET_FAILURE;
				}

				if(fieldEntry.fieldId == 8746)
				{
					if ((ret = rsslDecodeBuffer(dIter, &fidBufferValue)) == RSSL_RET_SUCCESS)
					{
						//snprintf(&pSession->symbolListEntry[SymbolListCounter]->name[0], 128, "%.*s", fidBufferValue.length, fidBufferValue.data);
						printf("SYMBOL2: %s", fidBufferValue.data);
					}
					else if (ret != RSSL_RET_BLANK_DATA)
					{
						printf("<%s> Error: %s (%d) encountered with rsslDecodeBuffer(). Error Text: %s\n",
							pSession->name,
							rsslRetCodeToString(ret), ret, rsslRetCodeInfo(ret));
						return ret;
					}
				}
				else if (fieldEntry.fieldId == 3422)
				{
					if ((ret = rsslDecodeBuffer(dIter, &fidBufferValue)) == RSSL_RET_SUCCESS)
					{
						snprintf(&pSession->symbolListEntry[SymbolListCounter]->name[0], 128, "%.*s", fidBufferValue.length, fidBufferValue.data);
						printf("SYMBOL: %s", pSession->symbolListEntry[SymbolListCounter]->name);
					}
					else if (ret != RSSL_RET_BLANK_DATA)
					{
						printf("<%s> Error: %s (%d) encountered with rsslDecodeBuffer(). Error Text: %s\n",
							pSession->name,
							rsslRetCodeToString(ret), ret, rsslRetCodeInfo(ret));
						return ret;
					}
				}
				else if (fieldEntry.fieldId == 32639)
				{

					int countStreamingChan = 0;

					rsslClearVector(&rsslVector);
					if ((ret = rsslDecodeVector(dIter, &rsslVector)) != RSSL_RET_SUCCESS)
					{
						printf("<%s> rsslDecodeVector() failed with return code: %d\n", pSession->name, ret);
						return RSSL_RET_FAILURE;
					}

					if (rsslVector.flags & RSSL_VTF_HAS_SET_DEFS)
					{
						/* must ensure it is the correct type - if map contents are element list, this is a field set definition db */
						if (rsslVector.containerType == RSSL_DT_ELEMENT_LIST)
						{
							rsslClearLocalElementSetDefDb(&elemSetDefDb);
							if ((ret = rsslDecodeLocalElementSetDefDb(dIter, &elemSetDefDb)) < RSSL_RET_SUCCESS)
							{
								/* decoding failures tend to be unrecoverable */
								printf("<%s> Error %s (%d) encountered with rsslDecodeLocalElementSetDefDb().  Error Text: %s\n",
									pSession->name,
									rsslRetCodeToString(ret), ret, rsslRetCodeInfo(ret));
								return ret;
							}
						}
					}

					/* decode the vector */
					while ((ret = rsslDecodeVectorEntry(dIter, &vectorEntry)) != RSSL_RET_END_OF_CONTAINER)
					{
						if(ret != RSSL_RET_SUCCESS)
						{
							printf("<%s> rsslDecodeVectorEntry() failed with return code: %d\n", pSession->name, ret);
							return RSSL_RET_FAILURE;
						}

						rsslClearElementList(&elemList);
						if ((ret = rsslDecodeElementList(dIter, &elemList, &elemSetDefDb)) != RSSL_RET_SUCCESS)
						{
							printf("<%s> rsslDecodeElementList() failed with return code: %d\n", pSession->name, ret);
							return RSSL_RET_FAILURE;
						}

						while ((ret = rsslDecodeElementEntry(dIter, &elemEntry)) != RSSL_RET_END_OF_CONTAINER)
						{
							if (ret != RSSL_RET_SUCCESS)
							{
								printf("<%s> rsslDecodeElementEntry() failed with return code: %d\n", pSession->name, ret);
								return RSSL_RET_FAILURE;
							}

							if (rsslBufferIsEqual(&elemEntry.name, &RSSL_ENAME_CHANNEL_ID))
							{
								if ((ret = rsslDecodeUInt(dIter, &pSession->symbolListEntry[SymbolListCounter]->streamingChannels[countStreamingChan].channelId)) == RSSL_RET_SUCCESS)
								{	
									printf(" StreamingChanId: %d", pSession->symbolListEntry[SymbolListCounter]->streamingChannels[countStreamingChan].channelId);
								}
								else
								{
									printf("<%s> Error: %s (%d) encountered with rsslDecodeUInt(). Error Text: %s\n",
										pSession->name,
										rsslRetCodeToString(ret), ret, rsslRetCodeInfo(ret));
									return ret;
								}
							}
							else if (rsslBufferIsEqual(&elemEntry.name, &RSSL_ENAME_DOMAIN))
							{
								if ((ret = rsslDecodeUInt(dIter, &pSession->symbolListEntry[SymbolListCounter]->streamingChannels[countStreamingChan].domain)) == RSSL_RET_SUCCESS)
								{	
									printf(" StreamingChanDom: %d", pSession->symbolListEntry[SymbolListCounter]->streamingChannels[countStreamingChan].domain);
								}
								else
								{
									printf("<%s> Error: %s (%d) encountered with rsslDecodeUInt(). Error Text: %s\n",
										pSession->name,
										rsslRetCodeToString(ret), ret, rsslRetCodeInfo(ret));
									return ret;
								}
							}

						}
						countStreamingChan++;

					}
				}
				else if (fieldEntry.fieldId == 32640)
				{
					int countGapChan = 0;

					rsslClearVector(&rsslVector);
					if ((ret = rsslDecodeVector(dIter, &rsslVector)) != RSSL_RET_SUCCESS)
					{
						printf("<%s> rsslDecodeVector() failed with return code: %d\n", pSession->name, ret);
						return RSSL_RET_FAILURE;
					}

					if (rsslVector.flags & RSSL_VTF_HAS_SET_DEFS)
					{
						/* must ensure it is the correct type - if map contents are element list, this is a field set definition db */
						if (rsslVector.containerType == RSSL_DT_ELEMENT_LIST)
						{
							rsslClearLocalElementSetDefDb(&elemSetDefDb);
							if ((ret = rsslDecodeLocalElementSetDefDb(dIter, &elemSetDefDb)) < RSSL_RET_SUCCESS)
							{
								/* decoding failures tend to be unrecoverable */
								printf("<%s> Error %s (%d) encountered with rsslDecodeLocalElementSetDefDb().  Error Text: %s\n",
									pSession->name,
									rsslRetCodeToString(ret), ret, rsslRetCodeInfo(ret));
								return ret;
							}

						}
					}

					/* decode the vector */
					while ((ret = rsslDecodeVectorEntry(dIter, &vectorEntry)) != RSSL_RET_END_OF_CONTAINER)
					{
						if(ret != RSSL_RET_SUCCESS)
						{
							printf("<%s> rsslDecodeVectorEntry() failed with return code: %d\n", pSession->name, ret);
							return RSSL_RET_FAILURE;
						}

						rsslClearElementList(&elemList);
						if ((ret = rsslDecodeElementList(dIter, &elemList, &elemSetDefDb)) != RSSL_RET_SUCCESS)
						{
							printf("<%s> rsslDecodeElementList() failed with return code: %d\n", pSession->name, ret);
							return RSSL_RET_FAILURE;
						}

						while ((ret = rsslDecodeElementEntry(dIter, &elemEntry)) != RSSL_RET_END_OF_CONTAINER)
						{
							if (ret != RSSL_RET_SUCCESS)
							{
								printf("<%s> rsslDecodeElementEntry() failed with return code: %d\n", pSession->name, ret);
								return RSSL_RET_FAILURE;
							}
							if (rsslBufferIsEqual(&elemEntry.name, &RSSL_ENAME_CHANNEL_ID))
							{
								if ((ret = rsslDecodeUInt(dIter, &pSession->symbolListEntry[SymbolListCounter]->gapChannels[countGapChan].channelId)) == RSSL_RET_SUCCESS)
								{	
									printf(" GapChanId: %d", pSession->symbolListEntry[SymbolListCounter]->gapChannels[countGapChan].channelId);
								}
								else
								{
									printf("<%s> Error: %s (%d) encountered with rsslDecodeUInt(). Error Text: %s\n",
										pSession->name,
										rsslRetCodeToString(ret), ret, rsslRetCodeInfo(ret));
									return ret;
								}
							}
							else if (rsslBufferIsEqual(&elemEntry.name, &RSSL_ENAME_DOMAIN))
							{
								if ((ret = rsslDecodeUInt(dIter, &pSession->symbolListEntry[SymbolListCounter]->gapChannels[countGapChan].domain)) == RSSL_RET_SUCCESS)
								{	
									printf(" GapChanlDom: %d", pSession->symbolListEntry[SymbolListCounter]->gapChannels[countGapChan].domain);
								}
								else
								{
									printf("<%s> Error: %s (%d) encountered with rsslDecodeUInt(). Error Text: %s\n",
										pSession->name,
										rsslRetCodeToString(ret), ret, rsslRetCodeInfo(ret));
									return ret;
								}
							}
						}
					}
					countGapChan++;
				}
			}
			SymbolListCounter++;
		}



		break;

	case RSSL_MC_STATUS:
		printf("\n<%s> Received Item StatusMsg for stream %i \n", pSession->name, msg->statusMsg.msgBase.streamId);
		if (msg->statusMsg.flags & RSSL_STMF_HAS_STATE)
		{
			rsslStateToString(&tempBuffer, &msg->statusMsg.state);
			printf("        %.*s\n\n", tempBuffer.length, tempBuffer.data);
		}

		break;

	case RSSL_MC_ACK:
		/* although this application only posts on MP (Market Price), 
		* ACK handler is provided for other domains to allow user to extend 
		* and post on MBO (Market By Order), MBP (Market By Price), SymbolList, and Yield Curve domains */
		printf("\n<%s> Received AckMsg for stream %i \n", pSession->name, msg->msgBase.streamId);

		/* get key */
		key = (RsslMsgKey *)rsslGetMsgKey(msg);

		/* print out item name from key if it has it */
		if (key)
		{
			printf("%.*s\nDOMAIN: %s\n", key->name.length, key->name.data, rsslDomainTypeToString(msg->msgBase.domainType));
		}
		printf("\tackId=%u\n", msg->ackMsg.ackId);
		if (msg->ackMsg.flags & RSSL_AKMF_HAS_SEQ_NUM)
			printf("\tseqNum=%u\n", msg->ackMsg.seqNum);
		if (msg->ackMsg.flags & RSSL_AKMF_HAS_NAK_CODE)
			printf("\tnakCode=%u\n", msg->ackMsg.nakCode);
		if (msg->ackMsg.flags & RSSL_AKMF_HAS_TEXT)
			printf("\ttext=%.*s\n", msg->ackMsg.text.length, msg->ackMsg.text.data);

		break;

	default:
		printf("\n<%s> Recieved Unhandled Item Msg Class: %d\n", pSession->name, msg->msgBase.msgClass);
		break;
	}

	return RSSL_RET_SUCCESS;
}
/* this function will decode a basic field list with several primitives embedded in it */
RsslRet exampleDecodeFieldList(RsslDecodeIterator *decIter)
{
	/* used to store and check return codes */
	RsslRet retVal;

	/* create a field list to decode into - 
	   since set data is not supported yet, there is nothing to put 
	   here except the count of the number of fields encoded in this 
	   message*/
	RsslFieldList fieldList = RSSL_INIT_FIELD_LIST;

	/* create field entry to decode into */
	RsslFieldEntry fieldEntry = RSSL_INIT_FIELD_ENTRY;

	/* create our primitives we will decode into */
	RsslDate rsslDate = RSSL_INIT_DATE;
	RsslTime rsslTime = RSSL_INIT_TIME;
	RsslReal rsslReal = RSSL_INIT_REAL;
	RsslArray rsslArray = RSSL_INIT_ARRAY;
	RsslDateTime rsslDateTime = RSSL_INIT_DATETIME;
	RsslQos rsslQos = RSSL_INIT_QOS;
	RsslState rsslState = RSSL_INIT_STATE;
	RsslBuffer rsslBuffer = RSSL_INIT_BUFFER;
	RsslEnum rsslEnum = 0;

	RsslUInt uInt;
	RsslInt Int;
	RsslBuffer arrayBuffer;
	RsslFloat Float;
	RsslDouble Double;

	/* decode into the field list structure */
	/* decode the field list header */
	if ((retVal = rsslDecodeFieldList(decIter, &fieldList, 0)) >= RSSL_RET_SUCCESS)
	{
		printf("\tField List Header Decoded\n");

		/* decode each field entry  */
		/* since this succeeded, we can decode fields until we
		reach the end of the fields - until RSSL_RET_END_OF_CONTAINER is returned */
		while ((retVal = rsslDecodeFieldEntry(decIter, &fieldEntry)) != RSSL_RET_END_OF_CONTAINER)
		{
			if (retVal < RSSL_RET_SUCCESS)
			{
				/* decoding failure tends to be unrecoverable */
				printf("Error %s (%d) encountered with rsslDecodeFieldEntry().  Error Text: %s\n", 
						rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
				return retVal;
			}
			else
			{
				/* A UPA application will typically use a field dictionary to decode field list content.  
				When using, code similar to the following can be used to look up type in field dictionary 
				and call correct primitive decode function */ 

				/*switch (fieldDict->entriesArray[fEntry->fieldId]->rwfType)
				{	
						case RSSL_DT_REAL:
							retVal = rsslDecodeReal(&decIter, &rsslReal);
						break;
						case RSSL_DT_DATE:
							retVal = rsslDecodeDate(&decIter, &rsslDate);
						break;
						/* full switch statement omitted to shorten sample code * /

				}*/

				/* decode our entry - this is typically based on the FID and what type 
				   it is as designated by the field dictionary.  Because we know
				   the FIDs we used to encode, we can handle them here without
	               looking up in the dictionary */

				/* FID encodings: 
				   FID 16 is RsslDate
				   FID 1080 is RsslUInt
				   FID 1081 is RsslUnit
				   FID 22 is RsslReal
		           FID 24 is RsslReal
				   FID 25 is RsslReal
				   FID 18 is RsslTime
				   FID 1021 is RsslArray
				   negative FIDs are user defined FIDs
	            */

				switch (fieldEntry.fieldId)
				{
					case 16: //RsslDate
					{
						if ((retVal = rsslDecodeDate(decIter, &rsslDate)) < RSSL_RET_SUCCESS)
						{
							printf("<%s:%d> Error decoding rsslDate.\n", __FILE__, __LINE__);
							return retVal;
						}

						printf("\t\tFID %d  RsslDate Decoded: %d-%d-%d\n", fieldEntry.fieldId, rsslDate.month, rsslDate.day, rsslDate.year);
					}
					break;

					case 22:
					case 24:
					case 25: //RsslReal
					{
						if ((retVal = rsslDecodeReal(decIter, &rsslReal)) < RSSL_RET_SUCCESS)
						{
							printf("<%s:%d> Error decoding rsslReal.\n", __FILE__, __LINE__);
							return retVal;
						}

						/* Handle blank case.  This should be done across all types, however in this example
						 * we know the only field sent as blank is FID 22 */
						if (retVal == RSSL_RET_BLANK_DATA)
							printf("\t\tFID %d  RsslReal Decoded as blank.\n", fieldEntry.fieldId);
						else
							printf("\t\tFID %d  RsslReal Decoded: hint: %d  value: "RTR_LLD"\n", fieldEntry.fieldId, rsslReal.hint, rsslReal.value);
					}
					break;

					case 1080:
					case 1081: //RsslUInt
					{
						if ((retVal = rsslDecodeUInt(decIter, &uInt)) < RSSL_RET_SUCCESS)
						{
							printf("<%s:%d> Error decoding rssl unsigned integer.\n", __FILE__, __LINE__);
							return retVal;
						}

						printf("\t\tFID %d Rssl Unsigned Integer Decoded: "RTR_LLU"\n", fieldEntry.fieldId, uInt);
					}
					break;

					
					case 18: //RsslTime
					{
						if ((retVal = rsslDecodeTime(decIter, &rsslTime)) < RSSL_RET_SUCCESS)
						{
							printf("<%s:%d> Error decoding rsslTime.\n", __FILE__, __LINE__);
							return retVal;
						}

						printf("\t\tFID %d  RsslTime Decoded: %d:%d:%d\n", fieldEntry.fieldId, rsslTime.hour, rsslTime.minute, rsslTime.second);
					}
					break;

					/* full switch statement omitted to shorten sample code */

					case 1021: //RsslArray
					{
						/* decode into the array structure header */
						if ((retVal = rsslDecodeArray(decIter, &rsslArray)) >= RSSL_RET_SUCCESS)
						{
						/* decode each array entry  */
							printf("\t\tFID %d RsslArray Decoded: [", fieldEntry.fieldId);
							while ((retVal = rsslDecodeArrayEntry(decIter, &arrayBuffer)) != RSSL_RET_END_OF_CONTAINER)
							{
								if (retVal < RSSL_RET_SUCCESS)
								{
									/* decoding failure tends to be unrecoverable */
									printf("Error %s (%d) encountered with rsslDecodeArrayEntry().  Error Text: %s\n", 
											rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
									return retVal;
								}
								else
								{
									/* decode array entry into primitive type */
									/* we can use the same decode iterator, or set the encoded
									   entry buffer onto a new iterator */
									if ((retVal = rsslDecodeUInt(decIter, &uInt)) < RSSL_RET_SUCCESS)
									{
										printf("<%s:%d> Error decoding rssl unsigned integer.\n", __FILE__, __LINE__);
										return retVal;
									}

									printf(" "RTR_LLU" ", uInt);
								}
							}
							printf("]\n");
						}
						else
						{
							/* decoding failure tends to be unrecoverable */
							printf("Error %s (%d) encountered with rsslDecodeArray().  Error Text: %s\n", 
								rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
							return retVal;
						}

					}
					break;

					case FID_INT:
					{
						if ((retVal = rsslDecodeInt(decIter, &Int)) < RSSL_RET_SUCCESS)
						{
							printf("<%s:%d> Error decoding rssl signed integer.\n", __FILE__, __LINE__);
							return retVal;
						}

						printf("\t\tFID %d Rssl signed Integer Decoded: "RTR_LLD"\n", fieldEntry.fieldId, Int);
					}
					break;

					case FID_FLOAT:
					{
						if ((retVal = rsslDecodeFloat(decIter, &Float)) < RSSL_RET_SUCCESS)
						{
							printf("<%s:%d> Error decoding rssl float.\n", __FILE__, __LINE__);
							return retVal;
						}

						printf("\t\tFID %d Rssl float Decoded: %f\n", fieldEntry.fieldId, Float);
					}
					break;

					case FID_DOUBLE:
					{
						if ((retVal = rsslDecodeDouble(decIter, &Double)) < RSSL_RET_SUCCESS)
						{
							printf("<%s:%d> Error decoding rssl double.\n", __FILE__, __LINE__);
							return retVal;
						}

						printf("\t\tFID %d Rssl double Decoded: %lf\n", fieldEntry.fieldId, Double);
					}
					break;

					case FID_DATETIME:
					{
						if ((retVal = rsslDecodeDateTime(decIter, &rsslDateTime)) < RSSL_RET_SUCCESS)
						{
							printf("<%s:%d> Error decoding rsslDateTime.\n", __FILE__, __LINE__);
							return retVal;
						}

						printf("\t\tFID %d  RsslDateTime Decoded: %d-%d-%d %d:%d:%d\n", fieldEntry.fieldId, 
									rsslDateTime.date.month, rsslDateTime.date.day, rsslDateTime.date.year, 
									rsslDateTime.time.hour, rsslDateTime.time.minute, rsslDateTime.time.second);
					}
					break;

					case FID_QOS:
					{
						if ((retVal = rsslDecodeQos(decIter, &rsslQos)) < RSSL_RET_SUCCESS)
						{
							printf("<%s:%d> Error decoding QOS.\n", __FILE__, __LINE__);
							return retVal;
						}

						printf("\t\tFID %d  Decoded QOS: %d %d %d %d %d\n", fieldEntry.fieldId, rsslQos.timeliness, rsslQos.rate, rsslQos.dynamic, rsslQos.rateInfo, rsslQos.timeInfo);
					}
					break;

					case FID_STATE:
					{
						if ((retVal = rsslDecodeState(decIter, &rsslState)) < RSSL_RET_SUCCESS)
						{
							printf("<%s:%d> Error decoding rsslState.\n", __FILE__, __LINE__);
							return retVal;
						}

						printf("\t\tFID %d  Decoded State: %d %d %d %s\n", fieldEntry.fieldId, rsslState.streamState, rsslState.dataState, rsslState.code, rsslState.text.data);
					}
					break;

					case FID_BUFFER:
					{
						if ((retVal = rsslDecodeBuffer(decIter, &rsslBuffer)) < RSSL_RET_SUCCESS)
						{
							printf("<%s:%d> Error decoding rsslBuffer.\n", __FILE__, __LINE__);
							return retVal;
						}

						printf("\t\tFID %d  RsslBuffer Decoded: %s\n", fieldEntry.fieldId, rsslBuffer.data);	// printf assumes its a null terminated character string 
					}
					break;

					case FID_ENUM:
					{
						if ((retVal = rsslDecodeEnum(decIter, &rsslEnum)) < RSSL_RET_SUCCESS)
						{
							printf("<%s:%d> Error decoding rsslEnum.\n", __FILE__, __LINE__);
							return retVal;
						}

						printf("\t\tFID %d  RsslEnum Decoded: %d\n", fieldEntry.fieldId, rsslEnum);
					}
					break;

					default:
						printf("\t\tUnexpected FID %d encountered!\n", fieldEntry.fieldId);
				}
			}
		}
	}
	else
	{
		/* decoding failure tends to be unrecoverable */
		printf("Error %s (%d) encountered with rsslDecodeFieldList().  Error Text: %s\n", 
			rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal));
		return retVal;
	}

	printf("\tFieldList Decoding Complete\n");

	return RSSL_RET_SUCCESS;
}
void simpleTunnelMsgHandlerProcessNewStream(SimpleTunnelMsgHandler *pSimpleTunnelMsgHandler,
		RsslTunnelStreamRequestEvent *pEvent)
{
	RsslErrorInfo errorInfo;
	RsslRet ret;
	RsslClassOfService cos;
	RsslBool rejectWithClassOfService = RSSL_FALSE;
	char *rejectString = NULL;

	printf("Received TunnelStream request on Stream ID %d.\n", pEvent->streamId);

	if (pSimpleTunnelMsgHandler == NULL)
		rejectString = (char*)"Provider tunnel stream limit reached."; // limited by MAX_TUNNEL_STREAMS in rsslProvider.h
	else if (pSimpleTunnelMsgHandler->tunnelStreamHandler.tunnelStreamOpenRequested)
		rejectString = (char*)"Consumer already has a tunnel stream open.";

	if (rejectString == NULL)
	{
		if ((rejectString = simpleTunnelMsgHandlerCheckRequestedClassOfService(pSimpleTunnelMsgHandler,
			pEvent, &cos)) != NULL)
			rejectWithClassOfService = RSSL_TRUE;
	}

	if (rejectString == NULL)
	{
		/* Accept the tunnel stream. */
		RsslReactorAcceptTunnelStreamOptions acceptOpts;

		rsslClearReactorAcceptTunnelStreamOptions(&acceptOpts);

		acceptOpts.statusEventCallback = tunnelStreamStatusEventCallback;
		acceptOpts.defaultMsgCallback = simpleTunnelMsgHandlerProviderMsgCallback;
		acceptOpts.userSpecPtr = (void*)pSimpleTunnelMsgHandler;

		acceptOpts.classOfService.authentication.type = cos.authentication.type;
		acceptOpts.classOfService.flowControl.type = RDM_COS_FC_BIDIRECTIONAL;
		acceptOpts.classOfService.dataIntegrity.type = RDM_COS_DI_RELIABLE;

		/* Use whichever protocol minor version is lower. */
		if (cos.common.protocolMinorVersion < acceptOpts.classOfService.common.protocolMinorVersion)
			acceptOpts.classOfService.common.protocolMinorVersion = cos.common.protocolMinorVersion;

		if ((ret = rsslReactorAcceptTunnelStream(pEvent, &acceptOpts, &errorInfo)) != RSSL_RET_SUCCESS)
			printf("rsslReactorAcceptTunnelStream() failed: %s(%s)\n", rsslRetCodeToString(ret), errorInfo.rsslError.text);

		pSimpleTunnelMsgHandler->tunnelStreamHandler.tunnelStreamOpenRequested = RSSL_TRUE;
	}
	else
	{
		/* Something didn't match our expectations, so reject the stream. */
		RsslReactorRejectTunnelStreamOptions rejectOpts;
		RsslClassOfService expectedCos;
		rsslClearReactorRejectTunnelStreamOptions(&rejectOpts);

		rejectOpts.state.streamState = RSSL_STREAM_CLOSED;
		rejectOpts.state.dataState = RSSL_DATA_SUSPECT;
		rejectOpts.state.text.data = rejectString;
		rejectOpts.state.text.length = (RsslUInt32)strlen(rejectOpts.state.text.data);

		if (rejectWithClassOfService)
		{
			/* Since we're rejecting due a Class-of-Service mismatch, 
			 * send a redirect state to the consumer. */
			rejectOpts.state.streamState = RSSL_STREAM_REDIRECTED;
			rejectOpts.state.dataState = RSSL_DATA_SUSPECT;

			/* Set what the class of service is expected to be. */
			rsslClearClassOfService(&expectedCos);
			expectedCos.authentication.type = cos.authentication.type;
			expectedCos.flowControl.type = RDM_COS_FC_BIDIRECTIONAL;
			expectedCos.dataIntegrity.type = RDM_COS_DI_RELIABLE;
			rejectOpts.pCos = &expectedCos;
		}
		else
		{
			rejectOpts.state.streamState = RSSL_STREAM_CLOSED;
			rejectOpts.state.dataState = RSSL_DATA_SUSPECT;
		}

		if ((ret = rsslReactorRejectTunnelStream(pEvent, &rejectOpts, &errorInfo)) != RSSL_RET_SUCCESS)
			printf("rsslReactorRejectTunnelStream() failed: %s(%s)\n", rsslRetCodeToString(ret), errorInfo.rsslError.text);
	}
}
/* this function will encode a basic field list with several primitives
   embedded in it */
RsslRet exampleEncodeFieldList(RsslEncodeIterator *encIter)
{
	/* used to store and check return values */
	RsslRet retVal;

	/* create and initialize field list structure */
	RsslFieldList fieldList = RSSL_INIT_FIELD_LIST;

	/* populate field list structure prior to call to rsslEncodeFieldListInit */
	/* NOTE: the fieldId, dictionaryId and fieldListNum values used for this example 
	* do not correspond to actual id values */

	/* indicate that standard data will be encoded and that dictionaryId and fieldListNum are included */
	fieldList.flags = RSSL_FLF_HAS_STANDARD_DATA | RSSL_FLF_HAS_FIELD_LIST_INFO;
	/* populate dictionaryId and fieldListNum with info needed to cross-reference fieldIds and cache */
	fieldList.dictionaryId = 2; 
	fieldList.fieldListNum = 5;

	/* begin encoding of field list - assumes that the RsslEncodeIterator pointed by the encIter pointer is already populated with
	   buffer and version information */

	/* Please note: here for simplicity, we did not use success parameter for rsslEncodeFieldListInit/rsslEncodeFieldListComplete calls. 
	   We are just simply displaying an error if it occurs and exit, thus RSSL_TRUE is used in replacement for success parameter */

	if ((retVal = rsslEncodeFieldListInit(encIter, &fieldList, 0, 0)) < RSSL_RET_SUCCESS)
	{
		/* print out message with return value string, value, and text */
		printf("Error %s (%d) encountered with rsslEncodeFieldListInit().  Error Text: %s\n", 
			rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		return retVal;
	}
	else
	{
		/* fieldListInit encoding was successful */
		/* create a single RsslFieldEntry and reuse for each entry */
		RsslFieldEntry fieldEntry = RSSL_INIT_FIELD_ENTRY;

		RsslBool success = RSSL_TRUE;

		/* stack allocate a date and populate {day, month, year} */
		RsslDate rsslDate = {30, 11, 2010};
		RsslReal rsslReal = RSSL_INIT_REAL;
		RsslTime rsslTime = RSSL_INIT_TIME;
		RsslArray rsslArray = RSSL_INIT_ARRAY;
		RsslDateTime rsslDateTime = RSSL_INIT_DATETIME;
		RsslQos rsslQos = RSSL_INIT_QOS;
		RsslState rsslState = RSSL_INIT_STATE;
		RsslEnum rsslEnum = 0;
		RsslBuffer rsslBuffer = RSSL_INIT_BUFFER;
	
		RsslUInt uInt = 23456;
		RsslInt Int = 65432;
		RsslFloat Float = 3.14f;
		RsslDouble Double = 3.1416;

		/* create a buffer for uInt to encode into -
		   This buffer can come from anywhere (stack allocated, malloc/new heap allocated).  Typically, for performance, the transport layer can provide
	       a pool of buffers for use and reuse that avoids the constant allocation/deallocation penalty.  
	       For this example I am stack allocating the buffer */
		char buf[10] = "";  //10 bytes is large enough for UInt encoding 

		/* create a RsslBuffer to set the buffer into */
		RsslBuffer encDecBuffer;
		RsslBuffer *pEncUInt = 0;

		/* set the data members to encDecBuffer buf and the length I created */
		encDecBuffer.data = buf;
		encDecBuffer.length = 10;

		printf("\tFieldList Header Encoded\n");
	
		/* FIRST Field Entry: encode entry from the RsslDate primitive type */
		/* populate and encode field entry with fieldId and dataType information for this field */
		fieldEntry.fieldId = 16; 
		fieldEntry.dataType = RSSL_DT_DATE;
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, &rsslDate)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded Date: %d-%d-%d\n", fieldEntry.fieldId, rsslDate.month, rsslDate.day, rsslDate.year);


		/* SECOND Field Entry: encode entry from the RsslUInt primitive type */
		fieldEntry.fieldId = 1080; 
		fieldEntry.dataType = RSSL_DT_UINT;
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, &uInt)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded Unsigned Integer: "RTR_LLU"\n", fieldEntry.fieldId, uInt);


		/* THIRD Field Entry: encode entry from preencoded buffer containing an encoded RsslUInt type */
		/* populate and encode field entry with fieldId and dataType information for this field */
		/* because we are re-populating all values on RsslFieldEntry, there is no need to clear it */
		fieldEntry.fieldId = 1081; 
		fieldEntry.dataType = RSSL_DT_UINT;

		/* assuming pEncUInt is an RsslBuffer with length and data properly populated */
		if ((retVal = getPreEncodedRsslUIntBuffer(&encDecBuffer, uInt)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with getPreEncodedRsslUIntBuffer().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		pEncUInt = &encDecBuffer;

		fieldEntry.encData.length = pEncUInt->length;
		fieldEntry.encData.data = pEncUInt->data;
		/* void* parameter is passed in as NULL because pre-encoded data is set on RsslFieldEntry itself */
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, NULL)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded Unsigned Integer: from preencoded buffer\n", fieldEntry.fieldId);


		/* FOURTH Field Entry: encode entry as a blank RsslReal primitive type */
		/* populate and encode field entry with fieldId and dataType information for this field */
		/* need to ensure that RsslFieldEntry is appropriatley cleared
		 * - clearing will ensure that encData is properly emptied */          
		rsslClearFieldEntry(&fieldEntry);

		fieldEntry.fieldId = 22; 
		fieldEntry.dataType = RSSL_DT_REAL;
		/* void* parameter is passed in as NULL and encData is empty due to clearing */
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, NULL)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded RsslReal as blank.\n", fieldEntry.fieldId);


		/* FIFTH Field Entry: encode entry for a RsslReal primitive type */
		fieldEntry.fieldId = 24; 
		fieldEntry.dataType = RSSL_DT_REAL; 
		rsslReal.hint = RSSL_RH_EXPONENT_2;
		rsslReal.value = 227;
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, &rsslReal)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded RsslReal: hint: %d  value: "RTR_LLD"\n", fieldEntry.fieldId, rsslReal.hint, rsslReal.value);

		
		/* SIXTH Field Entry: encode entry for another RsslReal primitive type */
		fieldEntry.fieldId = 25; 
		fieldEntry.dataType = RSSL_DT_REAL;  
		rsslReal.hint = RSSL_RH_EXPONENT_4;
		rsslReal.value = 22801;
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, &rsslReal)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded RsslReal: hint: %d  value: "RTR_LLD"\n", fieldEntry.fieldId, rsslReal.hint, rsslReal.value);


		/* SEVENTH Field Entry: encode entry for another RsslTime primitive type */
		fieldEntry.fieldId = 18; 
		fieldEntry.dataType = RSSL_DT_TIME;  
		rsslTime.hour = 8;
		rsslTime.minute = 39;
		rsslTime.second = 24;
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, &rsslTime)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}
		
		printf("\t\tFID %d  Encoded RsslTime: %d:%d:%d\n", fieldEntry.fieldId, rsslTime.hour, rsslTime.minute, rsslTime.second);


		/* EIGHTH Field Entry: encode entry from the RsslInt primitive type */
		fieldEntry.fieldId = FID_INT; 
		fieldEntry.dataType = RSSL_DT_INT;
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, &Int)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded signed Integer: "RTR_LLD"\n", fieldEntry.fieldId, Int);


		/* NINETH Field Entry: encode entry from the RsslFloat primitive type */
		fieldEntry.fieldId = FID_FLOAT; 
		fieldEntry.dataType = RSSL_DT_FLOAT;
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, &Float)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded float: %f\n", fieldEntry.fieldId, Float);


		/* TENTH Field Entry: encode entry from the RsslDouble primitive type */
		fieldEntry.fieldId = FID_DOUBLE; 
		fieldEntry.dataType = RSSL_DT_DOUBLE;
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, &Double)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded Double: %f\n", fieldEntry.fieldId, Double);


		/* ELEVENTH Field Entry: encode entry from the RsslDateTime primitive type */
		fieldEntry.fieldId = FID_DATETIME; 
		fieldEntry.dataType = RSSL_DT_DATETIME;
		rsslDateTime.date.month = 11;
		rsslDateTime.date.day = 15;
		rsslDateTime.date.year = 2011;
		rsslDateTime.time.hour = 8;
		rsslDateTime.time.minute = 39;
		rsslDateTime.time.second = 24;
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, &rsslDateTime)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded DateTime: %d-%d-%d %d:%d:%d\n", fieldEntry.fieldId, 
			rsslDateTime.date.month, rsslDateTime.date.day, rsslDateTime.date.year, rsslDateTime.time.hour, rsslDateTime.time.minute, rsslDateTime.time.second);

		/* TWELVETH Field Entry: encode entry from the RsslQos primitive type */
		fieldEntry.fieldId = FID_QOS; 
		fieldEntry.dataType = RSSL_DT_QOS;
		rsslQos.timeliness = RSSL_QOS_TIME_REALTIME;
		rsslQos.rate = RSSL_QOS_RATE_TICK_BY_TICK;
		rsslQos.dynamic = 1;
		rsslQos.rateInfo = 0;
		rsslQos.timeInfo = 0;
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, &rsslQos)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded QOS: %d %d %d %d %d\n", fieldEntry.fieldId, rsslQos.timeliness, rsslQos.rate, rsslQos.dynamic, rsslQos.rateInfo, rsslQos.timeInfo);


		/* THIRTEENTH Field Entry: encode entry from the RsslState primitive type */
		fieldEntry.fieldId = FID_STATE; 
		fieldEntry.dataType = RSSL_DT_STATE;
		rsslState.streamState = RSSL_STREAM_OPEN;
		rsslState.dataState = RSSL_DATA_OK;
		rsslState.code = RSSL_SC_NONE;
		rsslState.text.data = (char *)"Succeeded";
		rsslState.text.length = 10;		// include the null for printing
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, &rsslState)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded State: %d %d %d %s\n", fieldEntry.fieldId, rsslState.streamState, rsslState.dataState, rsslState.code, rsslState.text.data);

		/* FOURTEENTH Field Entry: encode entry from the RsslBuffer primitive type */
		fieldEntry.fieldId = FID_BUFFER; 
		fieldEntry.dataType = RSSL_DT_BUFFER;
		rsslBuffer.data = (char *)"BUFFEREXAMPLE";
		rsslBuffer.length = 14;			// include the null terminator to make it easier to print
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, &rsslBuffer)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded Buffer: %s\n", fieldEntry.fieldId, rsslBuffer.data);


		/* FIFTEENTH Field Entry: encode entry from the RsslEnum primitive type */
		fieldEntry.fieldId = FID_ENUM; 
		fieldEntry.dataType = RSSL_DT_ENUM;
		rsslEnum = 999;
		if ((retVal = rsslEncodeFieldEntry(encIter, &fieldEntry, &rsslEnum)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

		printf("\t\tFID %d  Encoded Enum: %d\n", fieldEntry.fieldId, rsslEnum);


		/* SIXTEENTH Field Entry: encode entry as a complex type, RsslArray primitive */
		/* populate and encode field entry with fieldId and dataType information for this field */
		/* need to ensure that RsslFieldEntry is appropriatley cleared
		 * - clearing will ensure that encData is properly emptied */          
		rsslClearFieldEntry(&fieldEntry);
		fieldEntry.fieldId = 1021; 
		fieldEntry.dataType = RSSL_DT_ARRAY;
		/* begin complex field entry encoding, we are not sure of the approximate max encoding length */
		if ((retVal = rsslEncodeFieldEntryInit(encIter, &fieldEntry, 0)) < RSSL_RET_SUCCESS)
		{
			/* error condition - switch our success value to false so we can roll back */
			success = RSSL_FALSE;
			/* print out message with return value string, value, and text */
			printf("Error %s (%d) encountered with rsslEncodeFieldEntryInit().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		}
		else
		{
			/* now encode nested container using its own specific encode functions */
			/* encode RsslReal values into the array */
			rsslArray.primitiveType = RSSL_DT_UINT;
			/* values are variable length */
			rsslArray.itemLength = 2;
			/* begin encoding of array - using same encIterator as field list */
			if ((retVal = rsslEncodeArrayInit(encIter, &rsslArray)) < RSSL_RET_SUCCESS)
			{
				/* error condition - switch our success value to false so we can roll back */
				success = RSSL_FALSE;
				/* print out message with return value string, value, and text */
				printf("Error %s (%d) encountered with rsslEncodeArrayInit().  Error Text: %s\n", 
					rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			}
			else
			{
				/*----- Continue encoding array entries. ---- */
				RsslUInt uInt1 = 10, uInt2 = 20, uInt3 = 30, uInt4 = 40;

				/* array encoding was successful */

				printf("\t\tFID %d Encoded RsslArray: [", fieldEntry.fieldId);

				/* encode first entry from a UInt from a primitive type */
				if ((retVal = rsslEncodeArrayEntry(encIter, NULL, &uInt1)) < RSSL_RET_SUCCESS)
				{
					/* error condition - switch our success value to false so we can roll back */
					success = RSSL_FALSE;
					printf("Error %s (%d) encountered with rsslEncodeArrayEntry().  Error Text: %s\n", 
						rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
				}
				printf(" "RTR_LLU" ", uInt1);

				/* encode second entry from a UInt from a primitive type */
				if ((retVal = rsslEncodeArrayEntry(encIter, NULL, &uInt2)) < RSSL_RET_SUCCESS)
				{
					/* error condition - switch our success value to false so we can roll back */
					success = RSSL_FALSE;
					printf("Error %s (%d) encountered with rsslEncodeArrayEntry().  Error Text: %s\n", 
						rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
				}
				printf(" "RTR_LLU" ", uInt2);

				/* encode third entry from a UInt from a primitive type */
				if ((retVal = rsslEncodeArrayEntry(encIter, NULL, &uInt3)) < RSSL_RET_SUCCESS)
				{
					/* error condition - switch our success value to false so we can roll back */
					success = RSSL_FALSE;
					printf("Error %s (%d) encountered with rsslEncodeArrayEntry().  Error Text: %s\n", 
						rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
				}
				printf(" "RTR_LLU" ", uInt3);

				/* encode forth entry from a UInt from a primitive type */
				if ((retVal = rsslEncodeArrayEntry(encIter, NULL, &uInt4)) < RSSL_RET_SUCCESS)
				{
					/* error condition - switch our success value to false so we can roll back */
					success = RSSL_FALSE;
					printf("Error %s (%d) encountered with rsslEncodeArrayEntry().  Error Text: %s\n", 
						rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); ;
				}
				printf(" "RTR_LLU" ", uInt4);

				/* encode fifth entry from a UInt from pre-encoded integer contained in a buffer */
				/* this buffer.data should point to encoded int and the length should be number of bytes encoded */
				if ((retVal = rsslEncodeArrayEntry(encIter, pEncUInt, NULL)) < RSSL_RET_SUCCESS)
				{
					/* error condition - switch our success value to false so we can roll back */
					success = RSSL_FALSE;
					printf("Error %s (%d) encountered with rsslEncodeArrayEntry().  Error Text: %s\n", 
						rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
				}
				printf(" <Preencoded> ]\n");
					
			}

			/* complete array encoding.  If success parameter is true, this will finalize encoding.  
			   If success parameter is false, this will roll back encoding prior to rsslEncodeArrayInit */
			if ((retVal = rsslEncodeArrayComplete(encIter, success)) < RSSL_RET_SUCCESS)
			{
				/* error condition - switch our success value to false so we can roll back */
				success = RSSL_FALSE;
				printf("Error %s (%d) encountered with rsslEncodeArrayComplete().  Error Text: %s\n", 
					rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			}

		}
		/* complete encoding of complex field entry.  If any array encoding failed, success is false */
		if ((retVal = rsslEncodeFieldEntryComplete(encIter, success)) < RSSL_RET_SUCCESS)
		{
			printf("Error %s (%d) encountered with rsslEncodeFieldEntryComplete().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			return retVal;
		}

	}

	/* complete fieldList encoding.  If success parameter is true, this will finalize encoding.  
	   If success parameter is false, this will roll back encoding prior to rsslEncodeFieldListInit */
	
	/* Please note: here for simplicity, we did not use success parameter for rsslEncodeFieldListInit/rsslEncodeFieldListComplete calls. 
	   We are just simply displaying an error if it occurs and exit, thus RSSL_TRUE is used in replacement for success parameter */

	if ((retVal = rsslEncodeFieldListComplete(encIter, RSSL_TRUE)) < RSSL_RET_SUCCESS)
	{
		printf("Error %s (%d) encountered with rsslEncodeFieldListComplete().  Error Text: %s\n", 
			rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		return retVal;
	}

	printf("\tFieldList Encoding Complete\n");

	return RSSL_RET_SUCCESS;

}
int main(int argc, char **argv)
{
	/* This example suite uses write descriptor in our server/Interactive Provider type examples in mainly 1 area with
	 * the I/O notification mechanism being used:
	 * 1) rsslFlush() calls used throughout the application (after module 1a), together with rsslWrite() calls, such
	 *    as in sendMessage() function. The write descriptor can be used to indicate when the socketId has write
	 *    availability and help with determining when the network is able to accept additional bytes for writing.
	 */

	/* This example suite also uses a clean FD sets and a dirty FD sets for I/O notification.

	 *		select() - a system call for examining the status of file_descriptors.
	 *					Tells us that there is data to read on the fds.

	 * Since select() modifies its file descriptor sets, if the call is being used in a loop, then the fd sets must
	 * be reinitialized before each call. Since they act as input/output parameters for the select() system call;
	 * they are read by and modified by the system call. When select() returns, the values have all been modified
	 * to reflect the set of file descriptors ready. So, every time before you call select(), you have to
	 * (re)initialize the fd_set values. Here we maintain 2 sets FD sets:
	 * a) clean FD sets so that we can repeatedly call select call
	 * b) dirty FD sets used in the actual select call (I/O notification mechanism)
	 * Typically, you reset the dirty FD sets to be equal to the clean FD sets before you call select().
	 */

	/**************************************************************************************************
			DECLARING VARIABLES
	**************************************************************************************************/
	/* UPA Server structure returned via the rsslBind call */
	RsslServer* upaSrvr = 0;

	RsslBool clientAccepted = RSSL_FALSE;

	char srvrPortNo[128];

	/* clean FD sets so that we can repeatedly call select call */
	fd_set cleanReadFds;
	fd_set cleanExceptFds;
	fd_set cleanWriteFds;

	/* dirty FD sets used in the actual select call (I/O notification mechanism) */
	fd_set useReadFds;
	fd_set useExceptFds;
	fd_set useWriteFds;

	struct timeval time_interval;
	int selRet;
	RsslRet retval = RSSL_RET_FAILURE;

	RsslError error;

	/* UPA Bind Options used in the rsslBind call. */
	RsslBindOptions bindOpts = RSSL_INIT_BIND_OPTS;

	/* UPA Accept Options used in the rsslAccept call */
	RsslAcceptOptions acceptOpts = RSSL_INIT_ACCEPT_OPTS;

	/* RsslInProgInfo Information for the In Progress Connection State */
	RsslInProgInfo inProgInfo = RSSL_INIT_IN_PROG_INFO;

	/* UPA channel management information */
	UpaChannelManagementInfo upaChannelManagementInfo;

	/* For this simple training app, the interactive provider only supports a single client. If the consumer disconnects,
	 * the interactive provider would simply exit.
	 *
	 * If you want the provider to support multiple client sessions at the same time, you need to implement support
	 * for multiple client sessions feature similar to what rsslProvider example is doing.
	 */
	upaChannelManagementInfo.upaChannel = 0;

	/* the default option parameters */
	/* server is running on port number 14002 */
	snprintf(srvrPortNo, 128, "%s", "14002");

	/* User specifies options such as address, port, and interface from the command line.
	 * User can have the flexibilty of specifying any or all of the parameters in any order.
	 */
	if (argc > 1)
	{
		int i = 1;

		while (i < argc)
		{
			if (strcmp("-p", argv[i]) == 0)
			{
				i += 2;
				snprintf(srvrPortNo, 128, "%s", argv[i-1]);
			}
			else
			{
				printf("Error: Unrecognized option: %s\n\n", argv[i]);
				printf("Usage: %s or\n%s [-p <SrvrPortNo>] \n", argv[0], argv[0]);
				exit(RSSL_RET_FAILURE);
			}
		}
	}

	/******************************************************************************************************************
				INITIALIZATION - USING rsslInitialize()
	******************************************************************************************************************/
	/*********************************************************
	 * Server/Provider Application Liefcycle Major Step 1:
	 * Initialize UPA Transport using rsslInitialize
	 * The first UPA Transport function that an application should call. This creates and initializes
	 * internal memory and structures, as well as performing any boot strapping for underlying dependencies.
	 * The rsslInitialize function also allows the user to specify the locking model they want applied
	 * to the UPA Transport.
	 *********************************************************/

	/* RSSL_LOCK_NONE is used since this is a single threaded application.
	 * For applications with other thread models (RSSL_LOCK_GLOBAL_AND_CHANNEL, RSSL_LOCK_GLOBAL),
	 * see the UPA C developers guide for definitions of other locking models supported by UPA
	 */
	if (rsslInitialize(RSSL_LOCK_NONE, &error) != RSSL_RET_SUCCESS)
	{
		printf("Error %s (%d) (errno: %d) encountered with rsslInitialize. Error Text: %s\n",
			rsslRetCodeToString(error.rsslErrorId), error.rsslErrorId, error.sysError, error.text);
		/* End application */
		exit(RSSL_RET_FAILURE);
	}

	FD_ZERO(&cleanReadFds);
	FD_ZERO(&cleanExceptFds);
	FD_ZERO(&cleanWriteFds);

	/* populate bind options, then pass to rsslBind function -
	 * UPA Transport should already be initialized
	 */
	bindOpts.serviceName = srvrPortNo;	/* server is running on default port number 14002 */
	bindOpts.pingTimeout = 60;			/* servers desired ping timeout is 60 seconds, pings should be sent every 20 */
	bindOpts.minPingTimeout = 30;		/* min acceptable ping timeout is 30 seconds, pings should be sent every 10 */

	/* set up buffering, configure for shared and guaranteed pools */
	bindOpts.guaranteedOutputBuffers = 1000;
	bindOpts.maxOutputBuffers = 2000;
	bindOpts.sharedPoolSize = 50000;
	bindOpts.sharedPoolLock = RSSL_TRUE;

	bindOpts.serverBlocking = RSSL_FALSE;		/* perform non-blocking I/O */
	bindOpts.channelsBlocking = RSSL_FALSE;		/* perform non-blocking I/O */
	bindOpts.compressionType = RSSL_COMP_NONE;	/* server does not desire compression for this connection */

	/* populate version and protocol with RWF information (found in rsslIterators.h) or protocol specific info */
	bindOpts.protocolType = RSSL_RWF_PROTOCOL_TYPE;	/* Protocol type definition for RWF */
	bindOpts.majorVersion = RSSL_RWF_MAJOR_VERSION;
	bindOpts.minorVersion = RSSL_RWF_MINOR_VERSION;

	/******************************************************************************************************************
				BINDING SETUP - USING rsslBind()
	******************************************************************************************************************/
	/*********************************************************
	 * Server/Provider Application Liefcycle Major Step 2:
	 * Create listening socket using rsslBind
	 * Establishes a listening socket connection, which supports connections from standard socket and HTTP
	 * rsslConnect users. Returns an RsslServer that represents the listening socket connection to the user.
	 * In the event of an error, NULL is returned and additional information can be found in the RsslError structure.
	 * Options are passed in via an RsslBindOptions structure. Once a listening socket is established, this
	 * RsslServer can begin accepting connections.
	 *********************************************************/

	/* Bind UPA server */
	if ((upaSrvr = rsslBind(&bindOpts, &error)) != NULL)
		printf("\nServer IPC descriptor = %d bound on port %d\n", upaSrvr->socketId, upaSrvr->portNumber);
	else
	{
		printf("Error %s (%d) (errno: %d) encountered with rsslBind. Error Text: %s\n",
			rsslRetCodeToString(error.rsslErrorId), error.rsslErrorId, error.sysError, error.text);

		/* End application, uninitialize to clean up first */
		rsslUninitialize();
		exit(RSSL_RET_FAILURE);
	}

	/* rsslBind listening socket connection was successful, add socketId to I/O notification mechanism and
	 * initialize connection
	 */
	/* Typical FD_SET use, this may vary depending on the I/O notification mechanism the application is using */
	FD_SET(upaSrvr->socketId, &cleanReadFds);
	FD_SET(upaSrvr->socketId, &cleanExceptFds);

	/******************************************************************************************************************
				MAIN LOOP TO SEE IF CONNECTION RECEIVED FROM CONSUMER
	******************************************************************************************************************/
	/* Main Loop #1 for detecting incoming client connections. The loop calls select() to wait for notification
	 * when the socketId of the server detects something to be read, this will check for incoming client connections.
	 * When a client successfully connects, a RsslChannel is returned which corresponds to this connection.
	 */

	/*
	 *If we want a non-blocking read call to the selector, we use select before read as read is a blocking call but select is not
	 *If we want a blocking read call to the selector, such that we want to wait till we get a message, we should use read without select.
	 *In the program below we will use select(), as it is non-blocking
	 */

	while (!clientAccepted)
	{
		useReadFds = cleanReadFds;
		useWriteFds = cleanWriteFds;
		useExceptFds = cleanExceptFds;

		/* Set a timeout value for waiting and checking messages received from incoming client connections. */
		/* On Linux platform, select() modifies timeout to reflect the amount of time not slept;
		 * most other implementations do not do this. (POSIX.1-2001 permits either behaviour.)
		 * This causes problems both when Linux code which reads timeout is ported to other operating systems,
		 * and when code is ported to Linux that reuses a struct timeval for multiple select()s
		 * in a loop without reinitializing it. Consider timeout to be undefined after select() returns.
		 *
		 * Note: You should reset the values of your timeout before you call select() every time.
		 */
		time_interval.tv_sec = 60;
		time_interval.tv_usec = 0;

		/* By employing an I/O notification mechanism (e.g. select, poll), an application can leverage a
		 * non-blocking I/O model, using the I/O notification to alert the application when data is available
		 * to read or when output space is available for writing to. The training examples are written from a
		 * non-blocking I/O perspective. Here, we use the select I/O notification mechanism in our examples.
		 */
		selRet = select(FD_SETSIZE, &useReadFds, &useWriteFds, &useExceptFds, &time_interval);

		if (selRet == 0)
		{
			/* no messages received from incoming connections, continue to wait and check for incoming client connections. */
		}
		else if (selRet > 0)
		{
			/* Received a response from the consumer. */

			/* On success, select() return the number of file descriptors contained in the three returned descriptor sets
			 * (that is, the total number of bits that are set in readfds, writefds, exceptfds)
			 */
			/* rsslInitChannel is called if read is triggered */
			if (FD_ISSET(upaSrvr->socketId, &useReadFds))
			{
				/* Use rsslAccept for incoming connections, read and write data to established connections, etc */

				/* Accept is typically called when servers socketId indicates activity */
				/* After a server is created using the rsslBind call, the rsslAccept call can be made. When the socketId of
				 * the server detects something to be read, this will check for incoming client connections. When a client
				 * successfully connects, a RsslChannel is returned which corresponds to this connection. This channel can
				 * be used to read or write with the connected client. If a clients connect message is not accepted, a
				 * negative acknowledgment is sent to the client and no RsslChannel is returned.
				 *
				 * For this simple training app, the interactive provider only supports a single client.
				 */

				/* populate accept options, then pass to rsslAccept function - UPA Transport should already be initialized */

				/*!< @brief If RSSL_TRUE, rsslAccept will send a NAK - even if the connection request is valid. */
				acceptOpts.nakMount = RSSL_FALSE; /* allow the connection */

				/*********************************************************
				 * Server/Provider Application Liefcycle Major Step 3:
				 * Accept connection using rsslAccept
				 * This step is performed per connected client/connection/channel
				 * Uses the RsslServer that represents the listening socket connection and begins the accepting process
				 * for an incoming connection request. Returns an RsslChannel that represents the client connection.
				 * In the event of an error, NULL is returned and additional information can be found in the RsslError
				 * structure.
				 * The rsslAccept function can also begin the rejection process for a connection through the use of the
				 * RsslAcceptOptions structure.
				 * Once a connection is established and transitions to the RSSL_CH_STATE_ACTIVE state, this RsslChannel
				 * can be used for other transport operations.
				 *********************************************************/

				/* An OMM Provider application can begin the connection accepting or rejecting process by using the rsslAccept function */
				if ((upaChannelManagementInfo.upaChannel = rsslAccept(upaSrvr, &acceptOpts, &error)) == 0)
				{
					printf("Error %s (%d) (errno: %d) encountered with rsslAccept. Error Text: %s\n",
						rsslRetCodeToString(error.rsslErrorId), error.rsslErrorId, error.sysError, error.text);

					/* End application, uninitialize to clean up first */
					rsslUninitialize();
					exit(RSSL_RET_FAILURE);
				}
				else
				{
					/* For this simple training app, the interactive provider only supports one client session from the consumer. */

					printf("\nServer fd=%d: New client on Channel fd=%d\n",
						upaSrvr->socketId,upaChannelManagementInfo.upaChannel->socketId);

					/* Connection was successful, add socketId to I/O notification mechanism and initialize connection */
					/* Typical FD_SET use, this may vary depending on the I/O notification mechanism the application is using */
					FD_SET(upaChannelManagementInfo.upaChannel->socketId, &cleanReadFds);
					FD_SET(upaChannelManagementInfo.upaChannel->socketId, &cleanExceptFds);

					// set clientAccepted to be TRUE and exit the while Main Loop #1
					clientAccepted = RSSL_TRUE;
				}
			}
		}
		else if (selRet < 0)
		{
			/* On error, -1 is returned, and errno is set appropriately; the sets and timeout become undefined */
			printf("\nSelect error.\n");

			/* End application, uninitialize to clean up first */
			rsslUninitialize();
			exit(RSSL_RET_FAILURE);
		}
	}

	/******************************************************************************************************************
				SECOND MAIN LOOP TO CONNECTION ACTIVE - LISTENING/SENDING DATA AMD PING MANAGEMENT
	******************************************************************************************************************/
	/* Main Loop #2 for getting connection active and successful completion of the initialization process
	 * The loop calls select() to wait for notification
	 * Currently, the main loop would exit if an error condition is triggered or
	 * RsslChannel.state transitions to RSSL_CH_STATE_ACTIVE.
	 */
	while (upaChannelManagementInfo.upaChannel->state != RSSL_CH_STATE_ACTIVE)
	{
		useReadFds = cleanReadFds;
		useWriteFds = cleanWriteFds;
		useExceptFds = cleanExceptFds;

		/* Set a timeout value for getting connection active and successful completion of the initialization process */
		/* On Linux platform, select() modifies timeout to reflect the amount of time not slept;
		 * most other implementations do not do this. (POSIX.1-2001 permits either behaviour.)
		 * This causes problems both when Linux code which reads timeout is ported to other operating systems,
		 * and when code is ported to Linux that reuses a struct timeval for multiple select()s
		 * in a loop without reinitializing it. Consider timeout to be undefined after select() returns.
		 *
		 * Note: You should reset the values of your timeout before you call select() every time.
		 */
		time_interval.tv_sec = 60;
		time_interval.tv_usec = 0;

		/* By employing an I/O notification mechanism (e.g. select, poll), an application can leverage a
		 * non-blocking I/O model, using the I/O notification to alert the application when data is available
		 * to read or when output space is available for writing to. The training examples are written from a
		 * non-blocking I/O perspective. Here, we use the select I/O notification mechanism in our examples.
		 */
		selRet = select(FD_SETSIZE, &useReadFds, &useWriteFds, &useExceptFds, &time_interval);

		if (selRet == 0)
		{
			/* select has timed out, close the channel and exit */
			/* On success, select() return zero if the timeout expires before anything interesting happens. */
			printf("\nChannel initialization has timed out, exiting...\n");
			/* Closes channel, closes server, cleans up and exits the application. */
			closeChannelServerCleanUpAndExit(upaChannelManagementInfo.upaChannel, upaSrvr, RSSL_RET_FAILURE);
		}
		else if (selRet > 0)
		{
			/* Received a response from the consumer. */

			/* On success, select() return the number of file descriptors contained in the three returned descriptor sets
			 * (that is, the total number of bits that are set in readfds, writefds, exceptfds)
			 */

			/* Wait for channel to become active. After an RsslChannel is returned from the client's rsslConnect or server's rsslAccept call,
			 * the channel may need to continue the initialization process. This additional initialization is required
			 * as long as the RsslChannel.state is RSSL_CH_STATE_INITIALIZING. When using non-blocking I/O, this is the
			 * typical state that an RsslChannel will start from and it may require multiple initialization calls to
			 * transition to active. rsslInitChannel is typically called based on activity on the socketId, though a timer or
			 * looping can be used - the rsslInitChannel function should continue to be called until the
			 * connection becomes active, at which point reading and writing can begin.
			 */

			/* Indicates that an RsslChannel requires additional initialization. This initialization is typically additional
			 * connection handshake messages that need to be exchanged.
			 */

			/* rsslInitChannel is called if read or write or except is triggered */
			if (FD_ISSET(upaChannelManagementInfo.upaChannel->socketId, &useReadFds) || FD_ISSET(upaChannelManagementInfo.upaChannel->socketId, &useExceptFds))
			{

				/*********************************************************
				 * Server/Provider Application Liefcycle Major Step 4:
				 * Initialize until active using rsslInitChannel (UPA Transport connection establishment handshake)
				 * Continues initialization of an RsslChannel. This channel could originate from rsslConnect or rsslAccept.
				 * This function exchanges various messages to perform necessary UPA negotiations and handshakes to
				 * complete channel initialization.
				 * Requires the use of an RsslInProgInfo structure.
				 * The RsslChannel can be used for all additional transport functionality (e.g. reading, writing) once the
				 * state transitions to RSSL_CH_STATE_ACTIVE. If a connection is rejected or initialization fails,
				 * the state will transition to RSSL_CH_STATE_CLOSED.
				 *********************************************************/

				/* Internally, the UPA initialization process includes several actions. The initialization includes
				 * any necessary UPA connection handshake exchanges, including any HTTP or HTTPS negotiation.
				 * Compression, ping timeout, and versioning related negotiations also take place during the
				 * initialization process. This process involves exchanging several messages across the connection,
				 * and once all message exchanges have completed the RsslChannel.state will transition. If the connection
				 * is accepted and all types of negotiations completed properly, the RsslChannel.state will become
				 * RSSL_CH_STATE_ACTIVE. If the connection is rejected, either due to some kind of negotiation failure
				 * or because an RsslServer rejected the connection by setting nakMount to RSSL_TRUE, the RsslChannel.state
				 * will become RSSL_CH_STATE_CLOSED.
				 *
				 * Note:
				 * For both client and server channels, more than one call to rsslInitChannel can be required to complete
				 * the channel initialization process.
				 */
				if ((retval = rsslInitChannel(upaChannelManagementInfo.upaChannel, &inProgInfo, &error)) < RSSL_RET_SUCCESS)
				{
					printf("Error %s (%d) (errno: %d) encountered with rsslInitChannel fd=%d. Error Text: %s\n",
						rsslRetCodeToString(error.rsslErrorId), error.rsslErrorId, error.sysError, upaChannelManagementInfo.upaChannel->socketId, error.text);
					/* Closes channel, closes server, cleans up and exits the application. */
					closeChannelServerCleanUpAndExit(upaChannelManagementInfo.upaChannel, upaSrvr, RSSL_RET_FAILURE);
					break;
				}
				else
				{
					/* Handle return code appropriately */
			  		switch (retval)
					{
						/*!< (2)  Transport Success: Channel initialization is In progress, returned from rsslInitChannel. */
						case RSSL_RET_CHAN_INIT_IN_PROGRESS:
						{
							/* Initialization is still in progress, check the RsslInProgInfo for additional information */
							if (inProgInfo.flags & RSSL_IP_FD_CHANGE)
							{
								/* The rsslInitChannel function requires the use of an additional parameter, a RsslInProgInfo structure.
								 * Under certain circumstances, the initialization process may be required to create new or additional underlying connections.
								 * If this occurs, the application is required to unregister the previous socketId and register the new socketId with
								 * the I/O notification mechanism being used. When this occurs, the information is conveyed by the RsslInProgInfo and the RsslInProgFlags.
								 *
								 * RSSL_IP_FD_CHANGE indicates that a socketId change has occurred as a result of this call. The previous socketId has been
								 * stored in RsslInProgInfo.oldSocket so it can be unregistered with the I/O notification mechanism.
								 * The new socketId has been stored in RsslInProgInfo.newSocket so it can be registered with the
								 * I/O notification mechanism. The channel initialization is still in progress and subsequent calls
								 * to rsslInitChannel are required to complete it.
								 */
								printf("\nChannel In Progress - New FD: %d  Old FD: %d\n",upaChannelManagementInfo.upaChannel->socketId, inProgInfo.oldSocket );

								/* File descriptor has changed, unregister old and register new */
								FD_CLR(inProgInfo.oldSocket, &cleanReadFds);
								FD_CLR(inProgInfo.oldSocket, &cleanExceptFds);
								/* newSocket should equal upaChannelManagementInfo.upaChannel->socketId */
								FD_SET(upaChannelManagementInfo.upaChannel->socketId, &cleanReadFds);
								FD_SET(upaChannelManagementInfo.upaChannel->socketId, &cleanExceptFds);
							}
							else
							{
								printf("\nChannel %d In Progress...\n", upaChannelManagementInfo.upaChannel->socketId);
							}
						}
						break;

						/* channel connection becomes active!
						 * Once a connection is established and transitions to the RSSL_CH_STATE_ACTIVE state,
						 * this RsslChannel can be used for other transport operations.
						 */
						case RSSL_RET_SUCCESS:
						{
							printf("\nChannel on fd %d is now active - reading and writing can begin.\n", upaChannelManagementInfo.upaChannel->socketId);

							/*********************************************************
							 * Connection is now active. The RsslChannel can be used for all additional
							 * transport functionality (e.g. reading, writing) now that the state
							 * transitions to RSSL_CH_STATE_ACTIVE
							 *********************************************************/

							/* After channel is active, use UPA Transport utility function rsslGetChannelInfo to query RsslChannel negotiated
							 * parameters and settings and retrieve all current settings. This includes maxFragmentSize and negotiated
							 * compression information as well as many other values.
							 */
							if ((retval = rsslGetChannelInfo(upaChannelManagementInfo.upaChannel, &upaChannelManagementInfo.upaChannelInfo, &error)) != RSSL_RET_SUCCESS)
							{
								printf("Error %s (%d) (errno: %d) encountered with rsslGetChannelInfo. Error Text: %s\n",
									rsslRetCodeToString(error.rsslErrorId), error.rsslErrorId, error.sysError, error.text);

								/* Connection should be closed, return failure */
								/* Closes channel, closes server, cleans up and exits the application. */
								closeChannelServerCleanUpAndExit(upaChannelManagementInfo.upaChannel, upaSrvr, RSSL_RET_FAILURE);
							}

							printf( "Channel %d active. Channel Info:\n"
								"	Max Fragment Size: %u\n"
								"	Output Buffers: %u Max, %u Guaranteed\n"
								"	Input Buffers: %u\n"
								"	Send/Recv Buffer Sizes: %u/%u\n"
								"	Ping Timeout: %u\n"
								"	Connected component version: ",
								upaChannelManagementInfo.upaChannel->socketId,				/*!< @brief Socket ID of this UPA channel. */
								upaChannelManagementInfo.upaChannelInfo.maxFragmentSize,	/*!< @brief This is the max fragment size before fragmentation and reassembly is necessary. */
								upaChannelManagementInfo.upaChannelInfo.maxOutputBuffers,	/*!< @brief This is the maximum number of output buffers available to the channel. */
								upaChannelManagementInfo.upaChannelInfo.guaranteedOutputBuffers, /*!< @brief This is the guaranteed number of output buffers available to the channel. */
								upaChannelManagementInfo.upaChannelInfo.numInputBuffers,	/*!< @brief This is the number of input buffers available to the channel. */
								upaChannelManagementInfo.upaChannelInfo.sysSendBufSize,		/*!< @brief This is the systems Send Buffer size. This reports the systems send buffer size respective to the transport type being used (TCP, UDP, etc) */
								upaChannelManagementInfo.upaChannelInfo.sysRecvBufSize,		/*!< @brief This is the systems Receive Buffer size. This reports the systems receive buffer size respective to the transport type being used (TCP, UDP, etc) */
								upaChannelManagementInfo.upaChannelInfo.pingTimeout 		/*!< @brief This is the value of the negotiated ping timeout */
							);

							if (upaChannelManagementInfo.upaChannelInfo.componentInfoCount == 0)
								printf("(No component info)");
							else
							{
								RsslUInt32 count;
								for(count = 0; count < upaChannelManagementInfo.upaChannelInfo.componentInfoCount; ++count)
								{
									printf("%.*s",
										upaChannelManagementInfo.upaChannelInfo.componentInfo[count]->componentVersion.length,
										upaChannelManagementInfo.upaChannelInfo.componentInfo[count]->componentVersion.data);
									if (count < upaChannelManagementInfo.upaChannelInfo.componentInfoCount - 1)
										printf(", ");
								}
							}
							printf ("\n\n");

							/* do not allow new client to connect  */

							/* For this simple training app, the interactive provider only supports a single client. Once a client
							 * successfully connects, we call rsslCloseServer function to close the listening socket associated with the
							 * RsslServer. The connected RsslChannels will remain open. This allows the established connection to continue
							 * to send and receive data, while preventing new clients from connecting.
							 */

							/* clean up server */
							FD_CLR(upaSrvr->socketId, &cleanReadFds);
							FD_CLR(upaSrvr->socketId, &cleanExceptFds);

							/*********************************************************
							 * Server/Provider Application Liefcycle Major Step 7:
							 * Closes a listening socket associated with an RsslServer. This will release any pool based resources
							 * back to their respective pools, close the listening socket, and perform any additional necessary cleanup.
							 * Any established connections will remain open, allowing for continued information exchange.
							 *********************************************************/

							/* clean up server using rsslCloseServer call.
							 * If a server is being shut down, the rsslCloseServer function should be used to close the listening socket and perform
							 * any necessary cleanup. All currently connected RsslChannels will remain open. This allows applications to continue
							 * to send and receive data, while preventing new applications from connecting. The server has the option of calling
							 * rsslCloseChannel to shut down any currently connected applications.
							 * When shutting down the UPA Transport, the application should release any unwritten pool buffers.
							 * The listening socket can be closed by calling rsslCloseServer. This prevents any new connection attempts.
							 * If shutting down connections for all connected clients, the provider should call rsslCloseChannel for each connection client.
							*/
							if ((upaSrvr) && (rsslCloseServer(upaSrvr, &error) < RSSL_RET_SUCCESS))
							{
								printf("Error %s (%d) (errno: %d) encountered with rsslCloseServer.  Error Text: %s\n",
									rsslRetCodeToString(error.rsslErrorId), error.rsslErrorId, error.sysError, error.text);

								/* End application, uninitialize to clean up first */
								rsslUninitialize();
								exit(RSSL_RET_FAILURE);
							}

							// set upaSrvr to be NULL
							upaSrvr = 0;
						}
						break;
						default: /* Error handling */
						{
							printf("\nBad return value fd=%d <%s>\n",
								upaChannelManagementInfo.upaChannel->socketId, error.text);
							/* Closes channel, closes server, cleans up and exits the application. */
							closeChannelServerCleanUpAndExit(upaChannelManagementInfo.upaChannel, upaSrvr, RSSL_RET_FAILURE);
						}
						break;
					}
				}
			}
		}
		else if (selRet < 0)
		{
			/* On error, -1 is returned, and errno is set appropriately; the sets and timeout become undefined */
			printf("\nSelect error.\n");
			/* Closes channel, closes server, cleans up and exits the application. */
			closeChannelServerCleanUpAndExit(upaChannelManagementInfo.upaChannel, upaSrvr, RSSL_RET_FAILURE);
		}
	}
}
/*
 * Closes channel, closes server, cleans up and exits the application.
 * upaChannel - The channel to be closed
 * upaSrvr - The RsslServer that represents the listening socket connection to the user to be closed
 * code - if exit due to errors/exceptions
 */
void closeChannelServerCleanUpAndExit(RsslChannel* upaChannel, RsslServer* upaSrvr, int code)
{
	RsslRet	retval = 0;
	RsslError error;
	RsslBuffer* msgBuf = 0;

	/*********************************************************
	 * Server/Provider Application Liefcycle Major Step 6:
	 * Close connection using rsslCloseChannel (OS connection release handshake)
	 * rsslCloseChannel closes the server based RsslChannel. This will release any pool based resources
	 * back to their respective pools, close the connection, and perform any additional necessary cleanup.
	 * When shutting down the UPA Transport, the application should release all unwritten pool buffers.
	 * Calling rsslCloseChannel terminates the connection for each connection client.
	 *********************************************************/
	if ((upaChannel) && (retval = rsslCloseChannel(upaChannel, &error) < RSSL_RET_SUCCESS))
	{
		printf("Error %s (%d) (errno: %d) encountered with rsslCloseChannel. Error Text: %s\n",
			rsslRetCodeToString(error.rsslErrorId), error.rsslErrorId, error.sysError, error.text);
	}

	/*********************************************************
	 * Server/Provider Application Liefcycle Major Step 7:
	 * Closes a listening socket associated with an RsslServer. This will release any pool based resources
	 * back to their respective pools, close the listening socket, and perform any additional necessary cleanup.
	 * Any established connections will remain open, allowing for continued information exchange. If desired,
	 * the server can use rsslCloseChannel to shutdown any remaining connections.
	 *********************************************************/

	/* clean up server using rsslCloseServer call.
	 * If a server is being shut down, the rsslCloseServer function should be used to close the listening socket and perform
	 * any necessary cleanup. All currently connected RsslChannels will remain open. This allows applications to continue
	 * to send and receive data, while preventing new applications from connecting. The server has the option of calling
	 * rsslCloseChannel to shut down any currently connected applications.
	 * When shutting down the UPA Transport, the application should release any unwritten pool buffers.
	 * The listening socket can be closed by calling rsslCloseServer. This prevents any new connection attempts.
	 * If shutting down connections for all connected clients, the provider should call rsslCloseChannel for each connection client.
	*/
	if ((upaSrvr) && (retval = rsslCloseServer(upaSrvr, &error) < RSSL_RET_SUCCESS))
	{
		printf("Error %s (%d) (errno: %d) encountered with rsslCloseServer.  Error Text: %s\n",
			rsslRetCodeToString(error.rsslErrorId), error.rsslErrorId, error.sysError, error.text);
	}

	/*********************************************************
	 * Server/Provider Application Liefcycle Major Step 8:
	 * Uninitialize UPA Transport using rsslUninitialize
	 * The last UPA Transport function that an application should call. This uninitializes internal data
	 * structures and deletes any allocated memory.
	 *********************************************************/

	/* All UPA Transport use is complete, must uninitialize.
	 * The uninitialization process allows for any heap allocated memory to be cleaned up properly.
	 */
	rsslUninitialize();

	/* For applications that do not exit due to errors/exceptions such as:
	 * Exits the application if the run-time has expired.
	 */
	if (code == RSSL_RET_SUCCESS)
		printf("\nUPA Interactive Provider Training application successfully ended.\n");

	/* End application */
	exit(code);
}
Exemple #27
0
/* This function encodes a map which contains nested field lists */
RsslRet exampleEncodeMap(RsslEncodeIterator *encIter)
{
	/* use this to store and check return codes */
	RsslRet retVal;
	RsslBool success = RSSL_TRUE;

	/* create and initialize our map structure */
	RsslMap rsslMap = RSSL_INIT_MAP;

	/* populate map structure prior to call to rsslEncodeMapInit */
	/* NOTE: the key names used for this example may not correspond to actual name values */

	/* indicate that summary data and a total count hint will be encoded  */
	rsslMap.flags = RSSL_MPF_HAS_SUMMARY_DATA | RSSL_MPF_HAS_TOTAL_COUNT_HINT;
	/* populate maps keyPrimitiveType and containerType */
	rsslMap.containerType = RSSL_DT_FIELD_LIST;
	rsslMap.keyPrimitiveType = RSSL_DT_UINT;
	/* populate total count hint with approximate expected entry count */
	rsslMap.totalCountHint = 3;


	/* begin encoding of map - assumes that the RsslEncodeIterator pointed by the encIter pointer is already populated with
	   buffer and version information, store return value to determine success or failure */
	/* expect summary data of approx. 256 bytes, no set definition data */
	if ((retVal = rsslEncodeMapInit(encIter, &rsslMap, 256, 0 )) < RSSL_RET_SUCCESS)
	{
		/* error condition - switch our success value to false so we can roll back */
		success = RSSL_FALSE;
		/* print out message with return value string, value, and text */
		printf("Error %s (%d) encountered with rsslEncodeMapInit().  Error Text: %s\n", 
			rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
	}
	else
	{
		/* mapInit encoding was successful */
		/* create a single RsslMapEntry and RsslFieldList and reuse for each entry */
		RsslMapEntry mapEntry = RSSL_INIT_MAP_ENTRY;
		RsslUInt entryKeyUInt = 0;

		/* create a buffer for uInt and field list to encode into -
		   This buffer can come from anywhere (stack allocated, malloc/new heap allocated).  Typically, for performance, the transport layer can provide
	       a pool of buffers for use and reuse that avoids the constant allocation/deallocation penalty.  
	       For this example I am stack allocating the buffer */
		char buf[10] = "";  //10 bytes is large enough for UInt encoding
		char buf2[500] = "";	//500 bytes is large enough for RsslFieldList encoding

		/* create a RsslBuffer to set the buffer into */
		RsslBuffer encDecBuffer, encDecBuffer2;
		RsslBuffer *pEncUInt = 0, *pEncFieldList = 0;

		/* set the data members to encDecBuffer buf and the length I created */
		encDecBuffer.data = buf;
		encDecBuffer.length = 10;

		encDecBuffer2.data = buf2;
		encDecBuffer2.length = 500;

		printf("\tRsslMap Header Encoded\n");

		/* encode expected summary data, init for this was done by rsslEncodeMapInit
	    - this type should match rsslMap.containerType */
		{
			printf("\tEncoding Summary Data\n");

			/* now encode nested container using its own specific encode functions */
			/* begin encoding of field list - using same encIterator as map list */

			if ((retVal = exampleEncodeFieldList(encIter)) < RSSL_RET_SUCCESS)
			{
				/* error condition - switch our success value to false so we can roll back */
				success = RSSL_FALSE;
				printf("<%s:%d> Error encoding field list.\n", __FILE__, __LINE__);
				printf("Error %s (%d) encountered with exampleEncodeFieldList().  Error Text: %s\n", 
					rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			}

			printf("\tSummary Data Encoding Complete\n");
		
		}
		/* complete encoding of summary data.  If any field list encoding failed, success is false */
		if ((retVal = rsslEncodeMapSummaryDataComplete(encIter, success)) < RSSL_RET_SUCCESS)	
		{
			/* error condition - switch our success value to false so we can roll back */
			success = RSSL_FALSE;
			printf("Error %s (%d) encountered with rsslEncodeMapSummaryDataComplete().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		}

		/* FIRST Map Entry: encode entry from non pre-encoded data and key.  Approx. encoded length unknown */
		mapEntry.action = RSSL_MPEA_UPDATE_ENTRY;
		entryKeyUInt = 1;
		if ((retVal = rsslEncodeMapEntryInit(encIter, &mapEntry, &entryKeyUInt, 0)) < RSSL_RET_SUCCESS)
		{
			/* error condition - switch our success value to false so we can roll back */
			success = RSSL_FALSE;
			printf("Error %s (%d) encountered with rsslEncodeMapEntryInit().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		}
		else
		/* encode contained field list - this type should match rsslMap.containerType */
		{
			printf("\tEncoding Map Entry (key: " RTR_LLU ") from non pre-encoded data and key\n", entryKeyUInt);

			/* now encode nested container using its own specific encode functions */
			/* clear, then begin encoding of field list - using same encIterator as map */

			if ((retVal = exampleEncodeFieldList(encIter)) < RSSL_RET_SUCCESS)
			{
				/* error condition - switch our success value to false so we can roll back */
				success = RSSL_FALSE;
				printf("<%s:%d> Error encoding field list.\n", __FILE__, __LINE__);
				printf("Error %s (%d) encountered with exampleEncodeFieldList().  Error Text: %s\n", 
					rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
			}
		
		}
		if ((retVal = rsslEncodeMapEntryComplete(encIter, success)) < RSSL_RET_SUCCESS)
		{
			/* error condition - switch our success value to false so we can roll back */
			success = RSSL_FALSE;
			printf("Error %s (%d) encountered with rsslEncodeMapEntryComplete().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		}

		printf("\tMap Entry (key: " RTR_LLU ") Encoding Complete\n", entryKeyUInt);

		
		/* SECOND Map Entry: encode entry from pre-encoded buffer containing an encoded RsslFieldList */
		/* because we are re-populating all values on RsslMapEntry, there is no need to clear it */

		mapEntry.action = RSSL_MPEA_ADD_ENTRY;
		entryKeyUInt = 2;

		printf("\tEncoding Map Entry (key: 2) from pre-encoded buffer\n");

		/* assuming pEncUInt RsslBuffer contains the pre-encoded key with length and data properly populated */
		if ((retVal = getPreEncodedRsslUIntBuffer(&encDecBuffer, entryKeyUInt)) < RSSL_RET_SUCCESS)
		{
			/* error condition - switch our success value to false so we can roll back */
			success = RSSL_FALSE;
			printf("Error %s (%d) encountered with getPreEncodedRsslUIntBuffer().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		}

		pEncUInt = &encDecBuffer;

		mapEntry.encKey.length = pEncUInt->length;
		mapEntry.encKey.data = pEncUInt->data;

		/* assuming pEncFieldList RsslBuffer contains the pre-encoded payload with data and length populated */
		if ((retVal = getPreEncodedRsslFieldListBuffer(&encDecBuffer2)) < RSSL_RET_SUCCESS)
		{
			/* error condition - switch our success value to false so we can roll back */
			success = RSSL_FALSE;
			printf("Error %s (%d) encountered with getPreEncodedRsslFieldListBuffer().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		}

		pEncFieldList = &encDecBuffer2;

		mapEntry.encData.length = pEncFieldList->length;
		mapEntry.encData.data = pEncFieldList->data;

		/* void* parameter is passed in as NULL because pre-encoded key is set on RsslMapEntry itself */
		if ((retVal = rsslEncodeMapEntry(encIter, &mapEntry, NULL)) < RSSL_RET_SUCCESS)
		{
			/* error condition - switch our success value to false so we can roll back */
			success = RSSL_FALSE;
			printf("Error %s (%d) encountered with rsslEncodeMapEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		}

		printf("\tMap Entry (key: " RTR_LLU ") Encoding Complete\n", entryKeyUInt);


		/* THIRD Map Entry: encode entry with delete action.  Delete actions have no payload */
		/* need to ensure that RsslMapEntry is appropriatley cleared
		 * - clearing will ensure that encData and encKey are properly emptied */          
		rsslClearMapEntry(&mapEntry);

		mapEntry.action = RSSL_MPEA_DELETE_ENTRY;
		entryKeyUInt = 3;

		printf("\tEncoding Map Entry (key: " RTR_LLU ") with delete action with no payload\n", entryKeyUInt);

		/* void* parameter is passed in as pointer to key primitive value.  encData is empty for delete */
		if ((retVal = rsslEncodeMapEntry(encIter, &mapEntry, &entryKeyUInt)) < RSSL_RET_SUCCESS) 
		{
			/* error condition - switch our success value to false so we can roll back */
			success = RSSL_FALSE;
			printf("Error %s (%d) encountered with rsslEncodeMapEntry().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		}

		printf("\tMap Entry (key: " RTR_LLU ") Encoding Complete\n", entryKeyUInt);

	}

	/* complete map encoding.  If success parameter is true, this will finalize encoding.  
	   If success parameter is false, this will roll back encoding prior to rsslEncodeMapInit */
	if ((retVal = rsslEncodeMapComplete(encIter, success)) < RSSL_RET_SUCCESS) 
	{
		printf("Error %s (%d) encountered with rsslEncodeMapEntry().  Error Text: %s\n", 
			rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		return retVal;
	}
	
	printf("\tRsslMap Encoding Complete\n");

	return RSSL_RET_SUCCESS;
}
/* this function will encode a basic Element list with several primitives embedded in it */
RsslRet exampleEncodeElementList(RsslEncodeIterator *encIter)
{
	/* create a single RsslElementEntry and reuse for each entry */
	RsslElementEntry elemEntry = RSSL_INIT_ELEMENT_ENTRY;

	/* used to store and check return values */
	RsslRet retVal;

	/* create and initialize element list structure */
	RsslElementList elementList = RSSL_INIT_ELEMENT_LIST;

	/* various data types used during encoding */
	RsslTime rsslTime = {10, 21, 16, 777};
	RsslUInt rsslUInt = 17;
	RsslInt rsslInt = 13;

	/* populate element list structure prior to call to rsslEncodeElementListInit */

	/* indicate that standard data will be encoded and that elementListNum is included */
	elementList.flags = RSSL_ELF_HAS_STANDARD_DATA | RSSL_ELF_HAS_ELEMENT_LIST_INFO;

	/* populate elementListNum with info needed to cache */
	elementList.elementListNum = 5;

	/* begin encoding of element list - assumes that the RsslEncodeIterator pointed by the encIter pointer is already populated with buffer and version information */

	/* Please note: here for simplicity, we did not use success parameter for rsslEncodeElementListInit/rsslEncodeElementListComplete calls. 
	   We are just simply displaying an error if it occurs and exit, thus RSSL_TRUE is used in replacement for success parameter */

	if ((retVal = rsslEncodeElementListInit(encIter, &elementList, 0, 0)) < RSSL_RET_SUCCESS)
	{
		/* print out message with return value string, value, and text */
		printf("Error %s (%d) encountered with rsslEncodeElementListInit().  Error Text: %s\n", 
			rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		return retVal;
	}

	/* FIRST Element Entry: encode entry from the RsslTime primitive type */
	/* populate and encode element entry with name and dataType information for this element */
	elemEntry.name.data = (char *)"Element - RsslTime";
	elemEntry.name.length = 20; 
	elemEntry.dataType = RSSL_DT_TIME;
	printf("\tEncoding Element Entry (name: %.*s) \n", elemEntry.name.length, elemEntry.name.data);
	retVal = rsslEncodeElementEntry(encIter, &elemEntry, &rsslTime); 
	printf("\t\tEncoded RsslTime: %d:%d:%d\n", rsslTime.hour, rsslTime.minute, rsslTime.second);

	/* SECOND Element Entry: encode entry from the RsslInt primitive type */
	/* populate and encode element entry with name and dataType information for this element */
	elemEntry.name.data = (char *)"Element - RsslInt";
	elemEntry.name.length = 17; 
	elemEntry.dataType = RSSL_DT_INT;
	printf("\tEncoding Element Entry (name: %.*s) \n", elemEntry.name.length, elemEntry.name.data);
	retVal = rsslEncodeElementEntry(encIter, &elemEntry, &rsslInt); 		
	printf("\t\tEncoded signed Integer: " RTR_LLD "\n", rsslInt);

	/* THIRD Element Entry: encode entry from the RsslUInt primitive type */
	/* populate and encode element entry with name and dataType information for this element */
	elemEntry.name.data = (char *)"Element - RsslUInt";
	elemEntry.name.length = 18; 
	elemEntry.dataType = RSSL_DT_UINT;
	printf("\tEncoding Element Entry (name: %.*s) \n", elemEntry.name.length, elemEntry.name.data);
	retVal = rsslEncodeElementEntry(encIter, &elemEntry, &rsslUInt); 
	printf("\t\tEncoded Unsigned Integer: " RTR_LLU "\n", rsslUInt);

	/* FOURTH Element Entry: encode entry from the RsslReal primitive type */
	/* populate and encode element entry with name and dataType information for this element */
	rsslClearElementEntry(&elemEntry);	// clear this to ensure a blank field
	elemEntry.name.data = (char *)"Element - RsslReal - Blank";
	elemEntry.name.length = 26; 
	elemEntry.dataType = RSSL_DT_REAL;
	printf("\tEncoding Element Entry (name: %.*s) \n", elemEntry.name.length, elemEntry.name.data);
	retVal = rsslEncodeElementEntry(encIter, &elemEntry, NULL);		/* this encodes a blank */
	printf("\t\tEncoded RsslReal: Blank\n");

	/* complete elementList encoding.  If success parameter is true, this will finalize encoding.  
	   If success parameter is false, this will roll back encoding prior to rsslEncodeElementListInit */
	
	if ((retVal = rsslEncodeElementListComplete(encIter, RSSL_TRUE)) < RSSL_RET_SUCCESS)
	{
		printf("Error %s (%d) encountered with rsslEncodeElementListComplete().  Error Text: %s\n", 
				rsslRetCodeToString(retVal), retVal, rsslRetCodeInfo(retVal)); 
		return retVal;
	}

	printf("\tElementList Encoding Complete\n");
	return RSSL_RET_SUCCESS;
}
int main(int argc, char **argv)
{
	/* For this simple training app, only a single channel/connection is used for the entire life of this app. */
	/* This example uses Unix I/O contents and basic TCP/IP like file descriptor and socket.*/

	/* This example suite uses write descriptor in our client/consumer type examples in mainly 2 areas with
	 * the I/O notification mechanism being used:
	 * Details of those functions could be found in API development guide.

	 * 1) rsslInitChannel() function which exchanges various messages to perform necessary UPA transport
	 *    negotiations and handshakes to complete channel initialization.
	 * 2) rsslFlush() calls used throughout the application (after module 1a), together with rsslWrite() calls, such
	 *    as in sendMessage() function. The write descriptor can be used to indicate when the socketId has write
	 *    availability and help with determining when the network is able to accept additional bytes for writing.
	 *
	 * For the RsslChannel initialization process, if using I/O, a client/consumer application should register the
	 * RsslChannel.socketId with the read, write, and exception file descriptor sets. When the write descriptor
	 * alerts the user that the socketId is ready for writing, rsslInitChannel is called (this sends the
	 * initial connection handshake message). When the read file descriptor alerts the user that the socketId
	 * has data to read, rsslInitChannel is called - this typically reads the next portion of the handshake.
	 * This process would continue until the connection is active.
	 *
	 * Typically, calls to rsslInitChannel are driven by I/O on the connection, however this can also be
	 * accomplished by using a timer to periodically call the function or looping on a call until the channel
	 * transitions to active or a failure occurs. Other than any overhead associated with the function call,
	 * there is no harm in calling rsslInitChannel more frequently than required. If no work is required at
	 * the current time, the function will return and indicate that connection is still in progress.
	 */

	/* This example suite also uses a clean FD sets and a dirty FD sets for I/O notification.

	 *		select() - a system call for examining the status of file_descriptors.
	 *					Tells us that there is data to read on the FDs.

	 * Since select() modifies its file descriptor sets, if the call is being used in a loop, then the fd sets must
	 * be reinitialized before each call. Since they act as input/output parameters for the select() system call;
	 * they are read by and modified by the system call. When select() returns, the values have all been modified
	 * to reflect the set of file descriptors ready. So, every time before you call select(), you have to
	 * (re)initialize the fd_set values. Here we maintain 2 sets FD sets:
	 * a) clean FD sets so that we can repeatedly call select call
	 * b) dirty FD sets used in the actual select call (I/O notification mechanism)
	 * Typically, you reset the dirty FD sets to be equal to the clean FD sets before you call select().
	 */

	/******************************************************************************************************************
				DECLARING VARIABLES
	******************************************************************************************************************/
	char srvrHostname[128], srvrPortNo[128], interfaceName[128];

	/* clean FD sets so that we can repeatedly call select call */
	fd_set cleanReadFds;
	fd_set cleanExceptFds;
	fd_set cleanWriteFds;

	/* dirty FD sets used in the actual select call (I/O notification mechanism) */
	fd_set useReadFds;
	fd_set useExceptFds;
	fd_set useWriteFds;

	struct timeval time_interval;
	int selRet;
	RsslRet retval = RSSL_RET_FAILURE;

	RsslError error;

	RsslConnectOptions cOpts  = RSSL_INIT_CONNECT_OPTS;

	/* RsslInProgInfo Information for the In Progress Connection State */
	RsslInProgInfo inProgInfo = RSSL_INIT_IN_PROG_INFO;

	/* UPA channel management information */
	UpaChannelManagementInfo upaChannelManagementInfo;

	/* For this simple training app, only a single channel/connection is used for the entire life of this app. */
	upaChannelManagementInfo.upaChannel = 0;

	/* the default option parameters */
	/* connect to server running on same machine */
	snprintf(srvrHostname, 128, "%s", "localhost");
	/* server is running on port number 14002 */
	snprintf(srvrPortNo, 128, "%s", "14002");
	/* use default NIC network interface card to bind to for all inbound and outbound data */
	snprintf(interfaceName, 128, "%s", "");

	/* User specifies options such as address, port, and interface from the command line.
	 * User can have the flexibilty of specifying any or all of the parameters in any order.
	 */
	if (argc > 1)
	{
		int i = 1;

		while (i < argc)
		{
			if (strcmp("-h", argv[i]) == 0)
			{
				i += 2;
				snprintf(srvrHostname, 128, "%s", argv[i-1]);
			}
			else if (strcmp("-p", argv[i]) == 0)
			{
				i += 2;
				snprintf(srvrPortNo, 128, "%s", argv[i-1]);
			}
			else if (strcmp("-i", argv[i]) == 0)
			{
				i += 2;
				snprintf(interfaceName, 128, "%s", argv[i-1]);
			}
			else
			{
				printf("Error: Unrecognized option: %s\n\n", argv[i]);
				printf("Usage: %s or\n%s [-h <SrvrHostname>] [-p <SrvrPortNo>] [-i <InterfaceName>] \n", argv[0], argv[0]);
				exit(RSSL_RET_FAILURE);
			}
		}
	}

	/******************************************************************************************************************
				INITIALIZATION - USING rsslInitialize()
	******************************************************************************************************************/
	/*********************************************************
	 * Client/Consumer Application Lifecycle Major Step 1:
	 * Initialize UPA Transport using rsslInitialize
	 * The first UPA Transport function that an application should call. This creates and initializes
	 * internal memory and structures, as well as performing any boot strapping for underlying dependencies.
	 * The rsslInitialize function also allows the user to specify the locking model they want applied
	 * to the UPA Transport.
	 *********************************************************/

	/* RSSL_LOCK_NONE is used since this is a single threaded application.
	 * For applications with other thread models (RSSL_LOCK_GLOBAL_AND_CHANNEL, RSSL_LOCK_GLOBAL),
	 * see the UPA C developers guide for definitions of other locking models supported by UPA
	 */
	if (rsslInitialize(RSSL_LOCK_NONE, &error) != RSSL_RET_SUCCESS)
	{
		printf("Error %s (%d) (errno: %d) encountered with rsslInitialize. Error Text: %s\n",
			rsslRetCodeToString(error.rsslErrorId), error.rsslErrorId, error.sysError, error.text);
		/* End application */
		exit(RSSL_RET_FAILURE);
	}

	FD_ZERO(&cleanReadFds);
	FD_ZERO(&cleanExceptFds);
	FD_ZERO(&cleanWriteFds);

	/* populate connect options, then pass to rsslConnect function -
	 * UPA Transport should already be initialized
	 */
	/* use standard socket connection */
	cOpts.connectionType = RSSL_CONN_TYPE_SOCKET; /*!< (0) Channel is a standard TCP socket connection type */
	cOpts.connectionInfo.unified.address = srvrHostname;
	cOpts.connectionInfo.unified.serviceName = srvrPortNo;
	cOpts.connectionInfo.unified.interfaceName = interfaceName;

	/* populate version and protocol with RWF information (found in rsslIterators.h) or protocol specific info */
	cOpts.protocolType = RSSL_RWF_PROTOCOL_TYPE; /* Protocol type definition for RWF */
	cOpts.majorVersion = RSSL_RWF_MAJOR_VERSION;
	cOpts.minorVersion = RSSL_RWF_MINOR_VERSION;

	/******************************************************************************************************************
				CONNECTION SETUP - USING rsslConnect()
	******************************************************************************************************************/
	/*********************************************************
	 * Client/Consumer Application Lifecycle Major Step 2:
	 * Connect using rsslConnect (OS connection establishment handshake)
	 * rsslConnect call Establishes an outbound connection, which can leverage standard sockets, HTTP,
	 * or HTTPS. Returns an RsslChannel that represents the connection to the user. In the event of an error,
	 * NULL is returned and additional information can be found in the RsslError structure.
	 * Connection options are passed in via an RsslConnectOptions structure.
	 *********************************************************/

	if ((upaChannelManagementInfo.upaChannel = rsslConnect(&cOpts, &error)) == 0)
	{
		printf("Error %s (%d) (errno: %d) encountered with rsslConnect. Error Text: %s\n",
			rsslRetCodeToString(error.rsslErrorId), error.rsslErrorId, error.sysError, error.text);

		/* End application, uninitialize to clean up first */
		rsslUninitialize();
		exit(RSSL_RET_FAILURE);
	}

	/* Connection was successful, add socketId to I/O notification mechanism and initialize connection */
	/* Typical FD_SET use, this may vary depending on the I/O notification mechanism the application is using */
	FD_SET(upaChannelManagementInfo.upaChannel->socketId, &cleanReadFds);
	FD_SET(upaChannelManagementInfo.upaChannel->socketId, &cleanExceptFds);

	/* for non-blocking I/O (default), write descriptor is set initially in case this end starts the message
	 * handshakes that rsslInitChannel() performs. Once rsslInitChannel() is called for the first time the
	 * channel can wait on the read descriptor for more messages. Without using the write descriptor, we would
	 * have to keep looping and calling rsslInitChannel to complete the channel initialization process, which
	 * can be CPU-intensive. We will set the write descriptor again if a FD_CHANGE event occurs.
	 */
	if (!cOpts.blocking)
	{
		if (!FD_ISSET(upaChannelManagementInfo.upaChannel->socketId, &cleanWriteFds))
			FD_SET(upaChannelManagementInfo.upaChannel->socketId, &cleanWriteFds);
	}

	printf("\nChannel IPC descriptor = %d\n", upaChannelManagementInfo.upaChannel->socketId);

	/******************************************************************************************************************
				MAIN LOOP TO SEE IF RESPONSE RECEIVED FROM PROVIDER
	******************************************************************************************************************/
	/* Main loop for getting connection active and successful completion of the initialization process
	 * The loop calls select() to wait for notification
	 * Currently, the main loop would exit if an error condition is triggered or
	 * RsslChannel.state transitions to RSSL_CH_STATE_ACTIVE.
	 */

	/*
	 *If we want a non-blocking read call to the selector, we use select before read as read is a blocking call but select is not
	 *If we want a blocking read call to the selector, such that we want to wait till we get a message, we should use read without select.
	 *In the program below we will use select(), as it is non-blocking
	 */

	while (upaChannelManagementInfo.upaChannel->state != RSSL_CH_STATE_ACTIVE)
	{
		useReadFds = cleanReadFds;
		useWriteFds = cleanWriteFds;
		useExceptFds = cleanExceptFds;

		/* Set a timeout value if the provider accepts the connection, but does not initialize it */
		/* On Linux platform, select() modifies timeout to reflect the amount of time not slept;
		 * most other implementations do not do this. (POSIX.1-2001 permits either behaviour.)
		 * This causes problems both when Linux code which reads timeout is ported to other operating systems,
		 * and when code is ported to Linux that reuses a struct timeval for multiple select()s
		 * in a loop without reinitializing it. Consider timeout to be undefined after select() returns.
		 *
		 * Note: You should reset the values of your timeout before you call select() every time.
		 */
		time_interval.tv_sec = 60;
		time_interval.tv_usec = 0;

		/* By employing an I/O notification mechanism (e.g. select, poll), an application can leverage a
		 * non-blocking I/O model, using the I/O notification to alert the application when data is available
		 * to read or when output space is available for writing to. The training examples are written from a
		 * non-blocking I/O perspective. Here, we use the select I/O notification mechanism in our examples.
		 */
		selRet = select(FD_SETSIZE, &useReadFds, &useWriteFds, &useExceptFds, &time_interval);

		if (selRet == 0)
		{
			/* select has timed out, close the channel and exit */
			/* On success, select() return zero if the timeout expires before anything interesting happens. */
			printf("\nChannel initialization has timed out, exiting...\n");
			/* Closes channel, cleans up and exits the application. */
			closeChannelCleanUpAndExit(upaChannelManagementInfo.upaChannel, RSSL_RET_FAILURE);
		}
		else if (selRet > 0)
		{
			/* Received a response from the provider. */

			/* On success, select() return the number of file descriptors contained in the three returned descriptor sets
			 * (that is, the total number of bits that are set in readfds, writefds, exceptfds)
			 */

			/* Wait for channel to become active. After an RsslChannel is returned from the client's rsslConnect or server's rsslAccept call,
			 * the channel may need to continue the initialization process. This additional initialization is required
			 * as long as the RsslChannel.state is RSSL_CH_STATE_INITIALIZING. When using non-blocking I/O, this is the
			 * typical state that an RsslChannel will start from and it may require multiple initialization calls to
			 * transition to active. rsslInitChannel is typically called based on activity on the socketId, though a timer or
			 * looping can be used - the rsslInitChannel function should continue to be called until the
			 * connection becomes active, at which point reading and writing can begin.
			 */

			/* Indicates that an RsslChannel requires additional initialization. This initialization is typically additional
			 * connection handshake messages that need to be exchanged.
			 */

			/* rsslInitChannel is called if read or write or except is triggered */
			if (FD_ISSET(upaChannelManagementInfo.upaChannel->socketId, &useReadFds) || FD_ISSET(upaChannelManagementInfo.upaChannel->socketId, &useWriteFds) || FD_ISSET(upaChannelManagementInfo.upaChannel->socketId, &useExceptFds))
			{
				/* Write descriptor is set initially in case this end starts the message handshakes that rsslInitChannel() performs.
				 * Once rsslInitChannel() is called for the first time the channel can wait on the read descriptor for more messages.
				 * We will set the write descriptor again if a FD_CHANGE event occurs. */
				FD_CLR(upaChannelManagementInfo.upaChannel->socketId, &cleanWriteFds);

				/*********************************************************
				 * Client/Consumer Application Lifecycle Major Step 3:
				 * Initialize until active using rsslInitChannel (UPA Transport connection establishment handshake)
				 * Continues initialization of an RsslChannel. This channel could originate from rsslConnect or rsslAccept.
				 * This function exchanges various messages to perform necessary UPA negotiations and handshakes to
				 * complete channel initialization.
				 * Requires the use of an RsslInProgInfo structure.
				 * The RsslChannel can be used for all additional transport functionality (e.g. reading, writing) once the
				 * state transitions to RSSL_CH_STATE_ACTIVE. If a connection is rejected or initialization fails,
				 * the state will transition to RSSL_CH_STATE_CLOSED.
				 *********************************************************/

				/* Internally, the UPA initialization process includes several actions. The initialization includes
				 * any necessary UPA connection handshake exchanges, including any HTTP or HTTPS negotiation.
				 * Compression, ping timeout, and versioning related negotiations also take place during the
				 * initialization process. This process involves exchanging several messages across the connection,
				 * and once all message exchanges have completed the RsslChannel.state will transition. If the connection
				 * is accepted and all types of negotiations completed properly, the RsslChannel.state will become
				 * RSSL_CH_STATE_ACTIVE. If the connection is rejected, either due to some kind of negotiation failure
				 * or because an RsslServer rejected the connection by setting nakMount to RSSL_TRUE, the RsslChannel.state
				 * will become RSSL_CH_STATE_CLOSED.
				 *
				 * Note:
				 * For both client and server channels, more than one call to rsslInitChannel can be required to complete
				 * the channel initialization process.
				 */
				if ((retval = rsslInitChannel(upaChannelManagementInfo.upaChannel, &inProgInfo, &error)) < RSSL_RET_SUCCESS)
				{
					printf("Error %s (%d) (errno: %d) encountered with rsslInitChannel fd=%d. Error Text: %s\n",
						rsslRetCodeToString(error.rsslErrorId), error.rsslErrorId, error.sysError, upaChannelManagementInfo.upaChannel->socketId, error.text);
					/* Closes channel, cleans up and exits the application. */
					closeChannelCleanUpAndExit(upaChannelManagementInfo.upaChannel, RSSL_RET_FAILURE);
					break;
				}
				else
				{
					/* Handle return code appropriately */
			  		switch (retval)
					{
						/*!< (2)  Transport Success: Channel initialization is In progress, returned from rsslInitChannel. */
						case RSSL_RET_CHAN_INIT_IN_PROGRESS:
						{
							/* Initialization is still in progress, check the RsslInProgInfo for additional information */
							if (inProgInfo.flags & RSSL_IP_FD_CHANGE)
							{
								/* The rsslInitChannel function requires the use of an additional parameter, a RsslInProgInfo structure.
								 * Under certain circumstances, the initialization process may be required to create new or additional underlying connections.
								 * If this occurs, the application is required to unregister the previous socketId and register the new socketId with
								 * the I/O notification mechanism being used. When this occurs, the information is conveyed by the RsslInProgInfo and the RsslInProgFlags.
								 *
								 * RSSL_IP_FD_CHANGE indicates that a socketId change has occurred as a result of this call. The previous socketId has been
								 * stored in RsslInProgInfo.oldSocket so it can be unregistered with the I/O notification mechanism.
								 * The new socketId has been stored in RsslInProgInfo.newSocket so it can be registered with the
								 * I/O notification mechanism. The channel initialization is still in progress and subsequent calls
								 * to rsslInitChannel are required to complete it.
								 */
								printf("\nChannel In Progress - New FD: %d  Old FD: %d\n",upaChannelManagementInfo.upaChannel->socketId, inProgInfo.oldSocket );

								/* File descriptor has changed, unregister old and register new */
								FD_CLR(inProgInfo.oldSocket, &cleanReadFds);
								FD_CLR(inProgInfo.oldSocket, &cleanWriteFds);
								FD_CLR(inProgInfo.oldSocket, &cleanExceptFds);
								/* newSocket should equal upaChannelManagementInfo.upaChannel->socketId */
								FD_SET(upaChannelManagementInfo.upaChannel->socketId, &cleanReadFds);
								FD_SET(upaChannelManagementInfo.upaChannel->socketId, &cleanWriteFds);
								FD_SET(upaChannelManagementInfo.upaChannel->socketId, &cleanExceptFds);
							}
							else
							{
								printf("\nChannel %d In Progress...\n", upaChannelManagementInfo.upaChannel->socketId);
							}
						}
						break;

						/* channel connection becomes active!
						 * Once a connection is established and transitions to the RSSL_CH_STATE_ACTIVE state,
						 * this RsslChannel can be used for other transport operations.
						 */
						case RSSL_RET_SUCCESS:
						{
							printf("\nChannel on fd %d is now active - reading and writing can begin.\n", upaChannelManagementInfo.upaChannel->socketId);

							/*********************************************************
							 * Connection is now active. The RsslChannel can be used for all additional
							 * transport functionality (e.g. reading, writing) now that the state
							 * transitions to RSSL_CH_STATE_ACTIVE
							 *********************************************************/

							/* After channel is active, use UPA Transport utility function rsslGetChannelInfo to query RsslChannel negotiated
							 * parameters and settings and retrieve all current settings. This includes maxFragmentSize and negotiated
							 * compression information as well as many other values.
							 */
							if ((retval = rsslGetChannelInfo(upaChannelManagementInfo.upaChannel, &upaChannelManagementInfo.upaChannelInfo, &error)) != RSSL_RET_SUCCESS)
							{
								printf("Error %s (%d) (errno: %d) encountered with rsslGetChannelInfo. Error Text: %s\n",
									rsslRetCodeToString(error.rsslErrorId), error.rsslErrorId, error.sysError, error.text);

								/* Connection should be closed, return failure */
								/* Closes channel, cleans up and exits the application. */
								closeChannelCleanUpAndExit(upaChannelManagementInfo.upaChannel, RSSL_RET_FAILURE);
							}

							printf( "Channel %d active. Channel Info:\n"
								"	Max Fragment Size: %u\n"
								"	Output Buffers: %u Max, %u Guaranteed\n"
								"	Input Buffers: %u\n"
								"	Send/Recv Buffer Sizes: %u/%u\n"
								"	Ping Timeout: %u\n"
								"	Connected component version: ",
								upaChannelManagementInfo.upaChannel->socketId,				/*!< @brief Socket ID of this UPA channel. */
								upaChannelManagementInfo.upaChannelInfo.maxFragmentSize,	/*!< @brief This is the max fragment size before fragmentation and reassembly is necessary. */
								upaChannelManagementInfo.upaChannelInfo.maxOutputBuffers,	/*!< @brief This is the maximum number of output buffers available to the channel. */
								upaChannelManagementInfo.upaChannelInfo.guaranteedOutputBuffers, /*!< @brief This is the guaranteed number of output buffers available to the channel. */
								upaChannelManagementInfo.upaChannelInfo.numInputBuffers,	/*!< @brief This is the number of input buffers available to the channel. */
								upaChannelManagementInfo.upaChannelInfo.sysSendBufSize,		/*!< @brief This is the systems Send Buffer size. This reports the systems send buffer size respective to the transport type being used (TCP, UDP, etc) */
								upaChannelManagementInfo.upaChannelInfo.sysRecvBufSize,		/*!< @brief This is the systems Receive Buffer size. This reports the systems receive buffer size respective to the transport type being used (TCP, UDP, etc) */
								upaChannelManagementInfo.upaChannelInfo.pingTimeout 		/*!< @brief This is the value of the negotiated ping timeout */
							);

							if (upaChannelManagementInfo.upaChannelInfo.componentInfoCount == 0)
								printf("(No component info)");
							else
							{
								RsslUInt32 count;
								for(count = 0; count < upaChannelManagementInfo.upaChannelInfo.componentInfoCount; ++count)
								{
									printf("%.*s",
										upaChannelManagementInfo.upaChannelInfo.componentInfo[count]->componentVersion.length,
										upaChannelManagementInfo.upaChannelInfo.componentInfo[count]->componentVersion.data);
									if (count < upaChannelManagementInfo.upaChannelInfo.componentInfoCount - 1)
										printf(", ");
								}
							}
							printf ("\n\n");
						}
						break;

						default: /* Error handling */
						{
							printf("\nBad return value fd=%d <%s>\n",
								upaChannelManagementInfo.upaChannel->socketId, error.text);
							/* Closes channel, cleans up and exits the application. */
							closeChannelCleanUpAndExit(upaChannelManagementInfo.upaChannel, RSSL_RET_FAILURE);
						}
						break;
					}
				}
			}
		}
		else if (selRet < 0)
		{
			/* On error, -1 is returned, and errno is set appropriately; the sets and timeout become undefined */
			printf("\nSelect error.\n");
			/* Closes channel, cleans up and exits the application. */
			closeChannelCleanUpAndExit(upaChannelManagementInfo.upaChannel, RSSL_RET_FAILURE);
		}
	}
}
RsslReactorCallbackRet simpleTunnelMsgHandlerProviderMsgCallback(RsslTunnelStream *pTunnelStream, RsslTunnelStreamMsgEvent *pEvent)
{
	RsslMsg *pRsslMsg = pEvent->pRsslMsg;
	RsslReactorChannel *pReactorChannel = pTunnelStream->pReactorChannel;
	SimpleTunnelMsgHandler *pSimpleTunnelMsgHandler = (SimpleTunnelMsgHandler*)pTunnelStream->userSpecPtr;

	/* Inspect the message and handle it accordingly. This is basically
	 * the same as the consumer's message callback but will respond to the
	 * client's authentication login message if one is received. */

	switch(pEvent->containerType)
	{
		case RSSL_DT_OPAQUE:
		{
			/* Read the text contained. */
			printf("Tunnel Stream %d received OPAQUE data: %.*s\n\n", 
					pTunnelStream->streamId, pEvent->pRsslBuffer->length, pEvent->pRsslBuffer->data);
			break;

		}

		case RSSL_DT_MSG:
		{

			switch(pRsslMsg->msgBase.domainType)
			{
				case RSSL_DMT_LOGIN:
				{
					RsslDecodeIterator dIter;
					RsslRDMLoginMsg loginMsg;
					char tmpMemory[1024];
					RsslBuffer memoryBuffer;
					RsslRet ret;
					RsslErrorInfo errorInfo;

					/* Use the ValueAdd RDM Decoder to decode the login message. */
					rsslClearDecodeIterator(&dIter);
					rsslSetDecodeIteratorRWFVersion(&dIter, pTunnelStream->classOfService.common.protocolMajorVersion,
						pTunnelStream->classOfService.common.protocolMinorVersion);
					rsslSetDecodeIteratorBuffer(&dIter, &pRsslMsg->msgBase.encDataBody);

					rsslClearBuffer(&memoryBuffer);
					memoryBuffer.length = sizeof(tmpMemory);
					memoryBuffer.data = tmpMemory;

					if ((ret = rsslDecodeRDMLoginMsg(&dIter, pRsslMsg, &loginMsg, &memoryBuffer, &errorInfo))
						!= RSSL_RET_SUCCESS)
					{
						printf("rsslDecodeRDMLoginMsg() failed: %s(%s)\n", rsslRetCodeToString(ret), errorInfo.rsslError.text);
						break;
					}

					switch(loginMsg.rdmMsgBase.rdmMsgType)
					{
					case RDM_LG_MT_REQUEST:
						{
							/* This is a login request, likely the client's authentication
							* request. Send a response to establish the tunnel stream. */

							RsslRDMLoginRefresh loginRefresh;
							RsslTunnelStreamSubmitOptions submitOpts;
							RsslTunnelStreamGetBufferOptions bufferOpts;
							RsslBuffer *pBuffer;
							RsslEncodeIterator eIter;
							RsslRet ret, ret2;
							RsslRDMLoginRequest *pLoginRequest = &loginMsg.request;

							printf("Received login request on tunnel stream(ID %d) with stream ID %d.\n", 
								pTunnelStream->streamId, pLoginRequest->rdmMsgBase.streamId);

							if (pLoginRequest->flags & RDM_LG_RQF_NO_REFRESH)
								break;

							rsslClearTunnelStreamGetBufferOptions(&bufferOpts);
							bufferOpts.size = 1024;
							if ((pBuffer = rsslTunnelStreamGetBuffer(pTunnelStream, &bufferOpts, &errorInfo))
								== NULL)
							{
								printf("rsslTunnelStreamGetBuffer failed: %s(%s)\n", rsslRetCodeToString(errorInfo.rsslError.rsslErrorId), &errorInfo.rsslError.text);
								break;
							}

							rsslClearRDMLoginRefresh(&loginRefresh);

							/* Set state information */
							loginRefresh.state.streamState = RSSL_STREAM_OPEN;
							loginRefresh.state.dataState = RSSL_DATA_OK;
							loginRefresh.state.code = RSSL_SC_NONE;
							loginRefresh.state.text.data = (char*)"Tunnel login accepted.";
							loginRefresh.state.text.length = (RsslUInt32)strlen(loginRefresh.state.text.data);

							/* Set stream ID */
							loginRefresh.rdmMsgBase.streamId = pLoginRequest->rdmMsgBase.streamId;

							/* Mark refresh as solicited since it is a response to a request. */
							loginRefresh.flags = RDM_LG_RFF_SOLICITED;

							/* Echo the userName, applicationId, applicationName, and position */
							loginRefresh.flags |= RDM_LG_RFF_HAS_USERNAME;
							loginRefresh.userName = pLoginRequest->userName;
							if (pLoginRequest->flags & RDM_LG_RQF_HAS_USERNAME_TYPE)
							{
								loginRefresh.flags |= RDM_LG_RFF_HAS_USERNAME_TYPE;
								loginRefresh.userNameType = pLoginRequest->userNameType;
							}

							loginRefresh.flags |= RDM_LG_RFF_HAS_APPLICATION_ID;
							loginRefresh.applicationId = pLoginRequest->applicationId;

							loginRefresh.flags |= RDM_LG_RFF_HAS_APPLICATION_NAME;
							loginRefresh.applicationName = pLoginRequest->applicationName;

							loginRefresh.flags |= RDM_LG_RFF_HAS_POSITION;
							loginRefresh.position = pLoginRequest->position;

							/* This provider does not support Single-Open behavior. */
							loginRefresh.flags |= RDM_LG_RFF_HAS_SINGLE_OPEN;
							loginRefresh.singleOpen = 0; 

							/* set the clear cache flag */
							loginRefresh.flags |= RDM_LG_RFF_CLEAR_CACHE;

							/* Leave all other parameters as default values. */

							/* Encode the refresh. */
							rsslClearEncodeIterator(&eIter);
							rsslSetEncodeIteratorRWFVersion(&eIter, pTunnelStream->classOfService.common.protocolMajorVersion,
								pTunnelStream->classOfService.common.protocolMinorVersion);
							if((ret = rsslSetEncodeIteratorBuffer(&eIter, pBuffer)) < RSSL_RET_SUCCESS)
							{
								printf("rsslSetEncodeIteratorBuffer(): Failed <%s>\n", errorInfo.rsslError.text);
								if ((ret2 = rsslTunnelStreamReleaseBuffer(pBuffer, &errorInfo)) != RSSL_RET_SUCCESS)
									printf("rsslTunnelStreamReleaseBuffer(): Failed <%d:%s>\n", ret2, errorInfo.rsslError.text);
								break;
							}

							if (rsslEncodeRDMLoginMsg(&eIter, (RsslRDMLoginMsg*)&loginRefresh, &pBuffer->length, &errorInfo) != RSSL_RET_SUCCESS)
							{
								printf("rsslEncodeRDMLoginMsg(): Failed <%s>\n", errorInfo.rsslError.text);
								if ((ret2 = rsslTunnelStreamReleaseBuffer(pBuffer, &errorInfo)) != RSSL_RET_SUCCESS)
									printf("rsslTunnelStreamReleaseBuffer(): Failed <%d:%s>\n", ret2, errorInfo.rsslError.text);
								break;
							}

							/* Message encoding complete; submit it. */
							rsslClearTunnelStreamSubmitOptions(&submitOpts);
							submitOpts.containerType = RSSL_DT_MSG;
							if ((ret = rsslTunnelStreamSubmit(pTunnelStream, pBuffer, &submitOpts, &errorInfo)) != RSSL_RET_SUCCESS)
							{
								printf("rsslTunnelStreamSubmit(): Failed <%s>\n", errorInfo.rsslError.text);
								if ((ret2 = rsslTunnelStreamReleaseBuffer(pBuffer, &errorInfo)) != RSSL_RET_SUCCESS)
									printf("rsslTunnelStreamReleaseBuffer(): Failed <%d:%s>\n", ret2, errorInfo.rsslError.text);
								break;
							}

							printf("Sent response to tunnel login request.\n\n");

							pSimpleTunnelMsgHandler->waitingForAuthenticationRequest = RSSL_FALSE;

							break;
						}

					case RDM_LG_MT_CLOSE:
						{
							/* Login close message. */
							RsslRDMLoginClose *pLoginClose = &loginMsg.close;

							printf("Received login close on tunnel stream(ID %d) with stream ID %d.\n", 
								pTunnelStream->streamId, pLoginClose->rdmMsgBase.streamId);
							break;
						}
					}


					break;
				}

				default:
				{
					/* Don't recognize this message. */
					printf("Received unhandled message in TunnelStream with stream ID %d, class %u(%s) and domainType %u(%s)\n\n",
						pRsslMsg->msgBase.streamId, 
						pRsslMsg->msgBase.msgClass, rsslMsgClassToString(pRsslMsg->msgBase.msgClass),
						pRsslMsg->msgBase.domainType, rsslDomainTypeToString(pRsslMsg->msgBase.domainType));
					break;
				}
			}
			break;
		}

		default:
		{
			printf("Received unhandled buffer containerType %d(%s) in tunnel stream %d\n\n", 
				pEvent->containerType, rsslDataTypeToString(pEvent->containerType), pTunnelStream->streamId);
			break;
		}
	}


	return RSSL_RC_CRET_SUCCESS; 
}