#if ((!defined lint) && (!defined OM_NO_RCS_ID))
static char *rcsid = "$Id:  $";
#endif
/********************************************************************************
//
//	file name   :	$Source:  $
//
//	purpose:	QNX specific code
//
//
//	author(s):	Ian Archer
//
//	date started:	March 2008
//
//	Licensed Materials - Property of IBM
//	© Copyright IBM Corporation 2002, 2008. All Rights Reserved.
//
//
// ---------------------------------------------------------------
//|							  RiCOSQNX.c                          |
// ---------------------------------------------------------------
*********************************************************************************/

#include "RiCOSQNX.h"
#include "RiCOSWrap.h"
#include "RiCList.h"
#include "RiCHdlCls.h"

#ifdef RIC_DISTRIBUTED_SYSTEM
#include <dox/RiDRoutingTable.h>
#include <dox/RiDSerMSg.h>
#include <dox/RiDSerializationManager.h>
#include <dox/RiDInstanceRegistry.h>
#include <dox/dox.h>
#include <stdio.h>
#include <oxf/RiCAddressSpace.h>
#endif /* RIC_DISTRIBUTED_SYSTEM */

#include <errno.h>

#ifdef _OMINSTRUMENT
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <sys/utsname.h>

#endif

#if ((!defined lint) && (!defined OM_NO_RCS_ID))
static char *hrcsid = RiCOSQNX_H;
#endif

/***************************************************/
/****				Default values				****/
/***************************************************/
const RiC_StackSizeType RiCOSDefaultStackSize = 1024;
const RiC_MessageQueueSizeType RiCOSDefaultMessageQueueSize = 100;
const RiC_ThreadPriorityType RiCOSDefaultThreadPriority = PRIORITY_NORMAL;

#ifdef	DEBUG_MEMORY

/*
** Debug alloc and free routines - which track allocations
*/
#define	NUM_STACK_ENTRIES		(8)
#define	NUM_MEMORY_ALLOCATIONS	(1000)

typedef struct {
	size_t		reqSize;							/* Size of allocation */
	void	  *	memPtr;								/* Allocated memory */
	void	  *	stackTrace[NUM_STACK_ENTRIES];		/* Call stack */
} MemoryAllocationRec_t;

static MemoryAllocationRec_t	allocations[NUM_MEMORY_ALLOCATIONS] = { 0 };

typedef struct {
	void	  *	prevFramePtr;
	void	  *	retAddr;
} StackFrame_t;

static unsigned int totalAllocations = 0;

static void * getFramePtr(void)
{
	asm("mov %ebp,%eax");
}

// Local forward declarations of malloc and free, we can't include stdlib.h as we override malloc and free in RiCOSQNX.h!
#undef malloc
#undef free

extern void * malloc(size_t);
extern void free(void *);

static void * debugMemAlloc(const size_t requestedSize)
{
	void		  * memPtr = NULL;
	unsigned int	entry;
	StackFrame_t  *	framePtr = NULL;
	unsigned int	frames;

	// First allocate the memory
	memPtr = malloc(requestedSize);

	// Now find a free entry to record the data
	for (entry = 0; entry < NUM_MEMORY_ALLOCATIONS; entry++)
	{
		if (allocations[entry].reqSize == 0)
		{
			allocations[entry].reqSize = requestedSize;
			allocations[entry].memPtr = memPtr;

			// Record the calling stack
			framePtr = getFramePtr();

			// Skip the first frame, as that is us!
			framePtr = framePtr->prevFramePtr;

			for (frames = 0; frames < NUM_STACK_ENTRIES; frames++)
			{
				if (framePtr != NULL)
				{
					allocations[entry].stackTrace[frames] = framePtr->retAddr;

					framePtr = framePtr->prevFramePtr;
				}
				else
				{
					allocations[entry].stackTrace[frames] = NULL;
				}
			}

			break;
		}
	}

	totalAllocations+= 1;

	return memPtr;
}

static void debugMemFree(const void *const memPtr)
{
	unsigned int	entry;

	// Find the recorded allocation
	for (entry = 0; entry < NUM_MEMORY_ALLOCATIONS; entry++)
	{
		if (allocations[entry].memPtr == memPtr)
		{
			// Mark this entry as available
			allocations[entry].reqSize = 0;

			totalAllocations-= 1;

			break;
		}
	}

	free((void *) memPtr);
}

/* Default to dynamic memory allocation */
RiCQNXOSAllocMemP_t RiCQNXOSMemoryAllocator = debugMemAlloc;
RiCQNXOSFreeMemP_t  RiCQNXOSMemoryDeallocator = debugMemFree;

#else // DEBUG_MEMORY

/* Default to dynamic memory allocation */
RiCQNXOSAllocMemP_t RiCQNXOSMemoryAllocator = RiCGetMemory;
RiCQNXOSFreeMemP_t  RiCQNXOSMemoryDeallocator = RiCReturnMemory;

#endif // DEBUG_MEMORY

/***************************************************/
/****			OS specific Methods				****/
/***************************************************/

static pthread_t MainThreadId = NULL;

void RiCOSEndApplication(RiC_INT32 errorCode)
{
	RiCTask* currentThread;
	RiCOSHandle threadOsHandle;
	pthread_t self_id;
	
#ifdef _OMINSTRUMENT
	ARCSD_instance();
	// ImA - Cannot close - as that kills this routine! ARCSD_closeConnection();
#endif
	currentThread = RiCTask_cleanupAllTasks();
	
#ifdef _OMINSTRUMENT
	// ImA - Cannot close - as that kills this routine! ARCSD_Destroy();
#endif
	
	RiCTimerManager_cleanup(RiCTimerManager_getSystemTimer());
	
	if (currentThread)
	{
		threadOsHandle = RiCOSTask_getOSHandle(RiCTask_getOSTask(currentThread));
		RiCTask_destroy(currentThread);
	}

	self_id = pthread_self();
	if (self_id != MainThreadId)
	{
		pthread_cancel(MainThreadId);
	}
	
	#ifdef RIC_DISTRIBUTED_SYSTEM
		RiDCloseMultipleAddressSpaces();
	#endif

	exit(0);
}

/**************/
/****/
void RiCOSOXFInitEpilog(void)
{
	// Nothing to do!
}

/***************************************************/
/****				OS Event Flag				****/
/***************************************************/
RiCBoolean RiCOSEventFlag_init(RiCOSEventFlag * const me)
{
	RiCBoolean status = RiCFALSE;

	if (me != NULL)
	{
		if (sem_init(&(me->hEventFlag), 0, 0) == 0)
		{
			status = RiCTRUE;
		}
	}

	return status;
}

/**************/
void RiCOSEventFlag_cleanup(RiCOSEventFlag * const me)
{
	(void) sem_destroy(&(me->hEventFlag));
}

/**************/
RiCOSEventFlag * RiCOSEventFlag_create()
{
	RiCOSEventFlag * me = (RiCOSEventFlag *) RiCQNXOSAllocMem(sizeof(RiCOSEventFlag));

	if (me != NULL)
	{
		(void) RiCOSEventFlag_init(me);
	}
	
	return me;
}

/**************/
void RiCOSEventFlag_destroy(RiCOSEventFlag * const me)
{
	if (me != NULL)
	{
		RiCOSEventFlag_cleanup(me);
		RiCQNXOSFreeMem(me);
	}
}

/**************/
RiCOSResult RiCOSEventFlag_wait(RiC_CONST_TYPE RiCOSEventFlag * const me,RiC_CONST_TYPE RiC_INT32 tminms )
{
	RiCOSResult		status = RiCOSFailure;

	if (me != NULL)
	{
		if (tminms == -1)
		{
			(void) sem_wait(&(me->hEventFlag));
			status = RiCOSSuccess;
		}
		else
		{
			// POSIX semaphores do not have timeouts.
			// To implement timeouts we loop on a try without wait
			// then sleep 10 ms until either semaphore is open ( ret value is 0)
			// or time is up.
			struct timespec tms;
			if (0 != sem_trywait(&(me->hEventFlag)))
			{
				timeUnit sleepTimeInterval = 10;

				int count = tminms / (int) sleepTimeInterval;
				int i = 0;

				for (i = 1; i < count ; i++)
				{
	      	      	tms.tv_sec = sleepTimeInterval/1000 ;
					tms.tv_nsec = (sleepTimeInterval % 1000)* 1000000;
	            	nanosleep(&tms, NULL);

					if (0 == sem_trywait(&(me->hEventFlag)))
					{
						status = RiCOSSuccess;
						break;
					}
				}
			}
			else
			{
				status = RiCOSSuccess;
			}
		}
	}

	return status;
}

/**************/
RiCOSResult RiCOSEventFlag_signal(RiC_CONST_TYPE RiCOSEventFlag * const me)
{
	RiCOSResult		status = RiCOSFailure;

	if (me != NULL)
	{
		if (sem_post(&(me->hEventFlag)) == 0)
		{
			status = RiCOSSuccess;
		}
	}

	return status;
}

/**************/
RiCOSResult RiCOSEventFlag_reset(RiC_CONST_TYPE RiCOSEventFlag * const me)
{
	RiCOSResult		status = RiCOSFailure;

	if (me != NULL)
	{
		while (sem_trywait(&(me->hEventFlag)) == 0)
			;

		status = RiCOSSuccess;
	}

	return status;
}

/***************************************************/
/****				OS Mutex					****/
/***************************************************/
RiCBoolean RiCOSMutex_init(RiCOSMutex * const me)
{
	RiCBoolean		status = RiCFALSE;

	if (me != NULL)
	{
		pthread_mutexattr_t attr;

		// Set attributes for recursive locking
		pthread_mutexattr_init(&attr);
		pthread_mutexattr_setrecursive(&attr, PTHREAD_RECURSIVE_ENABLE);

		if (pthread_mutex_init(&(me->hMutex), &attr) == EOK)
		{
			status = RiCTRUE;
		}
	}

	return status;
}

/**************/
void RiCOSMutex_cleanup(RiCOSMutex * const me)
{
	if (me != NULL)
	{
		(void) pthread_mutex_destroy(&(me->hMutex));
	}
}

/**************/
RiCOSMutex * RiCOSMutex_create()
{
	RiCOSMutex * me = (RiCOSMutex *) RiCQNXOSAllocMem(sizeof(RiCOSMutex));

	(void) RiCOSMutex_init(me);

	return me;
}

/**************/
void RiCOSMutex_destroy(RiCOSMutex * const me)
{
	if (me != NULL)
	{
		RiCOSMutex_cleanup(me);
		RiCQNXOSFreeMem(me);
	}
}


/***************************************************/
/****				OS Task						****/
/***************************************************/

RiCOSResult RiCOSTask_wrap(RiCOSTask * const me, RiCOSHandle threadOsHandle)
{
	RiCOSResult status = RiCOSFailure;

	if (me != NULL)
	{
		// Wrap the current thread
		me->hThread = threadOsHandle;
		me->isWrapperThread = RiCTRUE;
		me->endOSTaskInCleanup = RiCTRUE;
		memset(&me->suspEventFlag, 0, sizeof(me->suspEventFlag));
		me->suspend = RiCFALSE;

		MainThreadId = threadOsHandle;

		status = RiCOSSuccess;
	}

	return status;
}

/**************/
static void preExecFunc(void* vme)
{
	RiCOSTask *	me = (RiCOSTask *) vme;

	if (me != NULL)
	{
		if (me->suspend)
		{
			// Wait for the thread to be started
			sem_wait(&(me->suspEventFlag));

		}
		// Now start the actual thread
		me->cbkfunc(me->cbkparam);
	}
}

static void User1handler(int signumber)
{
	sigpause((int) SIGUSR2);
}

static void User2handler(int signumber)
{
	/*DO NOTHING */
}

typedef void*(*FormalThrCreateFunc)(void*);

/*lint -save -e715 (Symbol 'name' not referenced) */
RiCBoolean RiCOSTask_init(RiCOSTask * const me, RiC_CONST_TYPE RiCOSTaskEndCallBack tfunc, void * param, const RiC_CHAR8 *const name, const RiC_StackSizeType stackSize)
{
	RiCBoolean	status = RiCFALSE;

    pthread_attr_t tthread_attr;

	if (me != NULL)
	{
	    me->cbkfunc = tfunc;
		me->cbkparam = param;

		signal(SIGUSR1,User1handler);
		signal(SIGUSR2,User2handler);

		// Create a suspended thread
		sem_init (&(me->suspEventFlag), 0, 0);

	    pthread_attr_init( &tthread_attr );
	    pthread_attr_setstacksize( &tthread_attr, (size_t)stackSize );
	    pthread_attr_setdetachstate( &tthread_attr, PTHREAD_CREATE_DETACHED);
	    pthread_attr_setinheritsched( &tthread_attr, PTHREAD_INHERIT_SCHED );

	    me->isWrapperThread = RiCFALSE;
	    me->endOSTaskInCleanup = RiCFALSE;
		me->suspend = RiCTRUE;

		if (pthread_create(&(me->hThread), /* Handle */
			               &tthread_attr ,
			               (FormalThrCreateFunc)preExecFunc,
			               (void*)me) == EOK)
		{
			status = RiCTRUE;
		}
	}

	return status;
}
/*lint -restore */

/**************/
void RiCOSTask_cleanup(RiCOSTask * const me)
{
	if (me != NULL)
	{
		if (!me->isWrapperThread)
		{
			if (me->endOSTaskInCleanup)
			{
				RiCOSTaskEndCallBack theOSTaskEndClb = NULL;
				void * arg1 = NULL;
				RiCBoolean onMyTask = RiCOSTask_exeOnMyTask(me);

				/* get a callback function to end the os task */
				(void) RiCOSTask_getTaskEndClbk(me, &theOSTaskEndClb, &arg1, onMyTask);
				if (theOSTaskEndClb != NULL)
				{
					/* ending the os thread */
					(*theOSTaskEndClb)(arg1);
				}
			}
		}
		me->hThread = NULL;
	}
}

/**************/
RiCOSTask * RiCOSTask_create(RiC_CONST_TYPE RiCOSTaskEndCallBack tfunc, void * param, const RiC_CHAR8 *const name, const RiC_StackSizeType stackSize)
{
	RiCOSTask * me = (RiCOSTask *) RiCQNXOSAllocMem(sizeof(RiCOSTask));
	(void) RiCOSTask_init(me, tfunc, param, name, stackSize);
	return me;
}

/**************/
void RiCOSTask_destroy(RiCOSTask * const me)
{
	if (me != NULL)
	{
		RiCOSTask_cleanup(me);
		RiCQNXOSFreeMem(me);
	}
}

/**************/
RiCOSResult RiCOSTask_setPriority(RiC_CONST_TYPE RiCOSTask *const me, RiC_ThreadPriorityType pr)
{
	RiCOSResult status = RiCOSFailure;

	if (me != NULL)
	{
   		int s_policy;
   		struct sched_param s_param;

		pthread_getschedparam(me->hThread, &s_policy, &s_param );
   		s_param.sched_priority = pr;
		pthread_setschedparam(me->hThread, s_policy, &s_param );

		status = RiCOSSuccess;
	}

	return status;
}

/**************/
RiCOSResult RiCOSTask_suspend(RiC_CONST_TYPE RiCOSTask * const me)
{
	RiCOSResult status = RiCOSFailure;

	if (me != NULL)
	{
		pthread_kill(me->hThread,(int)SIGUSR1);
		status = RiCOSSuccess;
	}

	return status;
}

/**************/
RiCOSResult RiCOSTask_resume(RiC_CONST_TYPE RiCOSTask * const me)
{
	RiCOSResult status = RiCOSFailure;

	if (me != NULL)
	{
		pthread_kill(me->hThread,(int)SIGUSR2);
		status = RiCOSSuccess;
	}

	return status;
}

/**************/
RiCOSResult RiCOSTask_start(RiC_CONST_TYPE RiCOSTask * const me)
{
	RiCOSResult status = RiCOSFailure;

	if (me != NULL)
	{
		if(me->suspend)
		{
			if (sem_post(&(me->suspEventFlag)) == 0)
			{
				status = RiCOSSuccess;
			}
		}
		else
		{
			status = RiCOSTask_resume(me);
		}
	}

	return status;
}

/**************/
RiCOSHandle RiCOSTask_getCurrentTaskHandle()
{
	return (RiCOSHandle) pthread_self();
}

/**************/
RiCOSHandle RiCOSTask_getOSHandle(RiC_CONST_TYPE RiCOSTask * const me)
{
	if (me != NULL)
	{
		return (RiCOSHandle) (me->hThread);
	}
	else
	{
		return NULL;
	}
}

/**************/
int RiCOSTask_setEndOSTaskInCleanup(RiCOSTask * const me, RiC_CONST_TYPE RiCBoolean val)
{
	RiCOSResult status = RiCOSFailure;

	if (me != NULL)
	{
		me->endOSTaskInCleanup = val;
		status = RiCOSSuccess;
	}
	
	return status;
}

/**************/
RiCBoolean RiCOSTask_exeOnMyTask(RiC_CONST_TYPE RiCOSTask * const me)
{
	RiCOSHandle executedOsHandle;
	RiCOSHandle myOsHandle;
	RiCBoolean status = RiCFALSE;

	if (me != NULL)
	{
		/* a handle to the thread that executes the delete */
		executedOsHandle = RiCOSTask_getCurrentTaskHandle();
		/* a handle to this' 'thread' */
		myOsHandle = RiCOSTask_getOSHandle(me);

		status = ((executedOsHandle == myOsHandle) ? RiCTRUE : RiCFALSE);
	}

	return status;
}

/**************/
static const unsigned endThreadResult = 0;

void RiCOSTask_endMyTask(RiC_CONST_TYPE void * const hThread)
{
	/* real ending my thread */
	pthread_exit((void *) endThreadResult);
}

/**************/
RiCBoolean RiCOSTask_endOtherTask(void * handle)
{
	pthread_cancel((unsigned) handle);

	return RiCTRUE;
}

/**************/
int RiCOSTask_getTaskEndClbk(RiC_CONST_TYPE RiCOSTask * const me, RiCOSTaskEndCallBack * clb_p, void ** arg1_p, RiC_CONST_TYPE RiCBoolean onExecuteTask)
{
	RiCOSResult status = RiCOSFailure;

	if (me != NULL)
	{
		if (onExecuteTask)
		{
			/* asking for a callback to end my own thread */
			*clb_p = (RiCOSTaskEndCallBack) RiCOSTask_endMyTask;
			*arg1_p = (void *) me->hThread;
		}
		else
		{
			/* asking for a callback to end my thread by someone else */
			*clb_p  = (RiCOSTaskEndCallBack) RiCOSTask_endOtherTask;
			/* my thread handle */
			*arg1_p = (void *) me->hThread;
		}
		status = RiCOSSuccess;
	}
	
	return status;
}

/***************************************************/
/****					OS Timer				****/
/***************************************************/
static unsigned bridge(void *param)
{
	RiCQNXTimer * me = (RiCQNXTimer *)param;
	struct timespec tms;

	while(me)
	{
		tms.tv_sec = me->m_Time/1000 ;
		tms.tv_nsec = (me->m_Time % 1000)* 1000000;

		if ( me->m_Time > 0 )
		{
			//Real timer
			nanosleep(&tms, NULL);
		}
		else
		{
			//simulated timer
			// simulated timer simply yields until the next time the system idles
			sched_yield();
		}
		(*(me->cbkfunc))(me->param);
	}

	return 0; /* it is needed because of the task callback function signature */
}

/**************/
RiCBoolean RiCOSTimer_init(RiCOSTimer * const me, RiC_CONST_TYPE timeUnit ptime, void( *RiC_CONST_TYPE cbkfunc ) (void*), void * params)
{
    pthread_attr_t tthread_attr;
	int s_policy;
	struct sched_param s_param;
	RiCBoolean status = RiCFALSE;


	if (me != NULL)
	{
		me->m_Time = ptime;
		me->param = params;
		me->cbkfunc = cbkfunc;

	    pthread_attr_init( &tthread_attr );
	    pthread_attr_setstacksize( &tthread_attr, (size_t) RiCOSDefaultStackSize );
	    pthread_attr_setdetachstate( &tthread_attr, PTHREAD_CREATE_DETACHED);
	    pthread_attr_setinheritsched( &tthread_attr, PTHREAD_INHERIT_SCHED );

	    if (pthread_create(&(me->hThread), /* Handle */
			               &tthread_attr ,
			               (FormalThrCreateFunc)bridge,
			               (void*) me) == EOK)
		{
			pthread_getschedparam(me->hThread, &s_policy, &s_param );
   			s_param.sched_priority = PRIORITY_HIGH;
			pthread_setschedparam(me->hThread, s_policy, &s_param );

			status = RiCTRUE;
		}
	}

	return status;
}

/**************/
void RiCOSTimer_cleanup(RiCOSTimer * const me)
{
	if (me != NULL)
	{
		if (me->hThread)
		{
			RiCOSHandle executedOsHandle = RiCOSTask_getCurrentTaskHandle();
			/* a handle to this' 'thread' */
			RiCOSHandle myOsHandle = me->hThread;
			RiCBoolean onMyThread = ((executedOsHandle == myOsHandle) ? TRUE : FALSE);

			if (onMyThread)
			{
				RiCOSTask_endMyTask((void *) me->hThread);
			}
			else
			{
				(void) RiCOSTask_endOtherTask((void *) me->hThread);
			}
			me->hThread = 0;
		}
		me->cbkfunc = NULL;
		me->param = NULL;
	}
}

/**************/
RiCOSTimer * RiCOSTimer_create(timeUnit ptime, void( *RiC_CONST_TYPE cbkfunc ) ( void*), void * params)
{
	RiCOSTimer * me = (RiCOSTimer *) RiCQNXOSAllocMem(sizeof(RiCOSTimer));
	(void) RiCOSTimer_init(me, ptime, cbkfunc, params);
	return me;
}

/**************/
void RiCOSTimer_destroy(RiCOSTimer * const me)
{
	if (me != NULL)
	{
		RiCOSTimer_cleanup(me);
		RiCQNXOSFreeMem(me);
	}
}


/***************************************************/
/****			OS Message Queue				****/
/***************************************************/
#ifdef RIC_DISTRIBUTED_SYSTEM

/* Local functions */
static RiCBoolean initMessageQueue( RiCOSMessageQueue * const me,
									RiCBoolean shouldGrow,
									RiC_MessageQueueSizeType initSize,
									RiCBoolean ToDistributeQueue,
									const RiC_CHAR8 * queuePublishedName )
{	
	RiDInstanceRegistry* instanceRegistry = getRiDInstanceRegistry();
	char			  *	 QNXName = NULL;
	struct mq_attr		 queueAttr;
	RiCBoolean			 status = RiCFALSE;

	if (me != NULL)
	{
		me->m_ToDistributeQueue = ToDistributeQueue;
		me->m_pSavedData = NULL;

		if (initSize == 0)
		{
			me->m_QueueSize = QNX_DOX_MAX_MSGS;
		}
		else
		{
			me->m_QueueSize = initSize;
		}

		RiDInitQueueName(&(me->m_QueuePublishedName), queuePublishedName);

		// Create the underlying QNX queue
		QNXName = RiCQNXOSAllocMem(strlen(RiCString_getBuffer(&(me->m_QueuePublishedName))) + 1);
		if (QNXName != NULL)
		{
			sprintf(QNXName, "/%s", RiCString_getBuffer(&(me->m_QueuePublishedName)));

			memset(&queueAttr, 0, sizeof(queueAttr));
			queueAttr.mq_maxmsg = me->m_QueueSize;
			queueAttr.mq_msgsize = QNX_DOX_MSG_LEN;
			
			me->m_hQueue = mq_open(QNXName, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG, &queueAttr);

			RiCQNXOSFreeMem(QNXName);

			if (me->m_hQueue == -1)
			{
			#ifdef RID_DEBUG
				RiDReportErrorWithErrno("initMessageQueue : mq_open() error ", errno);
			#endif /* RID_DEBUG */
			}
			else
			{
				// Register the queue with the name server
				me->m_RegisteredId = -1;

				/*publish the queue, so it can be found by the sender */
				if (me->m_ToDistributeQueue)
				{
					if(instanceRegistry != NULL)
					{
						/* Register the message queue in the framework name service */
						me->m_RegisteredId = RiDInstanceRegistry_RegisterQueue(instanceRegistry,
																			   RiCString_getBuffer(&(me->m_QueuePublishedName)));
						if (me->m_RegisteredId < 0)
						{
						#ifdef RID_DEBUG
							RiDReportErrorWithErrno("publishMessageQueue : error ", me->m_RegisteredId);
						#endif /* RID_DEBUG */
						}
						else
						{
							status = RiCTRUE;
						}
					}
				}
				else
				{
					status = RiCTRUE;
				}
			}
		}
		else
		{
		#ifdef RID_DEBUG
			RiDReportErrorWithErrno("initMessageQueue : RiCQNXOSAllocMem failed - error ", errno);
		#endif /* RID_DEBUG */
		}
	}

	return status;
}
/******************************************************************/

/**************/
RiCBoolean RiCOSMessageQueue_initDistributed( RiCOSMessageQueue * const me, RiCBoolean shouldGrow, int initSize, const RiC_CHAR8 * queuePublishedName )
{
	return initMessageQueue( me, shouldGrow, initSize, RiCTRUE, queuePublishedName );
}

/**************/
RiCOSMessageQueue * RiCOSMessageQueue_createDistributed( RiCBoolean shouldGrow, int initSize, const RiC_CHAR8 * queuePublishedName )
{
	RiCOSMessageQueue * me = (RiCOSMessageQueue *) RiCQNXOSAllocMem( sizeof(RiCOSMessageQueue) );
	if (me != NULL)
	{
		RiCOSMessageQueue_initDistributed( me, shouldGrow, initSize, queuePublishedName );
	}
	return me;
}

/**************/
RhpString RiCOSMessageQueue_getMessageQueueId(RiCOSMessageQueue * const me)
{
	return (gen_ptr)(&(me->m_QueuePublishedName));
}

/**************/
RhpInteger RiCOSMessageQueue_getRegisteredId(RiCOSMessageQueue * const me)
{
	if(me != NULL)
	{
		return me->m_RegisteredId;
	}

	return -1;
}

/**************/
RiCBoolean RiCOSMessageQueue_init(RiCOSMessageQueue * const me, RiC_CONST_TYPE RiCBoolean shouldGrow, RiC_MessageQueueSizeType initSize)
{
	return initMessageQueue( me, shouldGrow, initSize, RiCFALSE, NULL );
}

/**************/
RiCBoolean RiCOSMessageQueue_isEmpty(RiC_CONST_TYPE RiCOSMessageQueue *const me)
{
	struct mq_attr			queueAttr;
	RiCBoolean				status = RiCFALSE;

	if ((me != NULL) && (me->m_hQueue != -1))
	{
		// check if new data is in the queue
		if (mq_getattr(me->m_hQueue, &queueAttr) != -1)
		{
			status = ((queueAttr.mq_curmsgs == 0) ? RiCTRUE : RiCFALSE);
		}
		else
		{
			#ifdef RID_DEBUG
				RiDReportError("RiCOSMessageQueue_isEmpty : Failed to get queue attributes");
			#endif
			status = RiCTRUE;
		}
	}

	return status;
}

/**************/

void UnregisterQueue(RiCOSMessageQueue * const me)
{
	RiDInstanceRegistry* instanceRegistry = getRiDInstanceRegistry();
	if (instanceRegistry != NULL)
	{
		RiCBoolean unregisterRes = RiDInstanceRegistry_UnregisterQueue(instanceRegistry, me->m_RegisteredId);
		if (unregisterRes != RiCTRUE)
		{
		#ifdef RID_DEBUG
			RiDReportError("RiCOSMessageQueue_cleanup : Failed to unregister queue");
		#endif
		}
	}			
}


/**************/
void RiCOSMessageQueue_cleanup(RiCOSMessageQueue * const me)
{
	if (me != NULL)
	{
		mq_close(me->m_hQueue);

		me->m_hQueue = -1;
		if (me->m_ToDistributeQueue == RiCTRUE)
		{
			UnregisterQueue(me);
		}
	}
}

/**************/
RiCOSMessageQueue * RiCOSMessageQueue_create(RiCBoolean shouldGrow, RiC_MessageQueueSizeType initSize)
{
	RiCOSMessageQueue * me = (RiCOSMessageQueue *) RiCQNXOSAllocMem(sizeof(RiCOSMessageQueue));
	(void) RiCOSMessageQueue_init(me, shouldGrow, initSize);
	return me;
}

/**************/
void RiCOSMessageQueue_destroy(RiCOSMessageQueue * const me)
{
	if (me != NULL)
	{
		RiCOSMessageQueue_cleanup(me);
		RiCQNXOSFreeMem(me);
	}
}

/**************/
RiCOSResult RiCOSMessageQueue_put(RiCOSMessageQueue * const me, gen_ptr message, RiC_CONST_TYPE RiCBoolean fromISR)
{
	RhpAddress	buffer = NULL;
	RhpPositive buffer_size;
	RiDSerMsg	serMsg;
	RiCOSResult	status = RiCOSFailure;

	if (me != NULL)
	{
		/* create message header */
		RiDSerMsg_Init( &serMsg, 0, 0, 0, 0, RiCTRUE, message, 0 );

		/* create buffer from the message header */
		if( RiDSerMsg_ToBuffer( &serMsg, &buffer, &buffer_size ) != 0 )
		{
			/* failed to create buffer */
		#ifdef RID_DEBUG
			RiDReportError("RiCOSMessageQueue_put : Failed to create buffer");
		#endif
		}
		else
		{
			/* Send the message to the queue, if it fits! */
			if (buffer_size <= QNX_DOX_MSG_LEN)
			{
				if (mq_send(me->m_hQueue, buffer, buffer_size, 0) == -1)
				{
					// Send failed
				#ifdef RID_DEBUG
					RiDReportError("RiCOSMessageQueue_put : Failed mq_send()");
				#endif
				}
				else
				{
					status = RiCOSSuccess;
				}

				// Message has been sent - so release the buffer
				if (buffer != NULL)
				{
					RiCQNXOSFreeMem( buffer );
					buffer = NULL;
				}
			}
			else
			{
				// Message is too long!
				if (buffer != NULL)
				{
					RiCQNXOSFreeMem(buffer);
					buffer = NULL;
				}
				#ifdef RID_DEBUG
					RiDReportErrorWithErrno("RiCOSMessageQueue_put : Msg is too big! ", buffer_size);
				#endif
			}
		}
	}

	return status;
}

/**************/
gen_ptr RiCOSMessageQueue_get(RiCOSMessageQueue * const me)
{
	gen_ptr						m = NULL;
	char					  *	bufPtr = NULL;
	RiDSerializationManager	  * serializationManager = NULL;
	ssize_t						actualLen = 0;

	/* safe programming */
	if ((me != NULL) && (me->m_hQueue != -1))
	{
		// Is there anything already available
		if (me->m_pSavedData == NULL)
		{
			if (!RiCOSMessageQueue_isEmpty(me))
			{
				bufPtr = (char *) RiCQNXOSAllocMem(QNX_DOX_MSG_LEN);

				if (bufPtr != NULL)
				{
					if ((actualLen = mq_receive(me->m_hQueue, bufPtr, QNX_DOX_MSG_LEN, NULL) ) == -1)
					{
						#ifdef RID_DEBUG
						RiDReportErrorWithErrno("RiCOSMessageQueue_get : mq_receive failed, returning error ", errno);			
						#endif

						RiCQNXOSFreeMem(bufPtr);
						bufPtr = NULL;
					}
				}
				else
				{
					#ifdef RID_DEBUG
					RiDReportErrorWithErrno("RiCOSMessageQueue_get : RiCQNXOSAllocMem failed, returning error ", errno);			
					#endif
				}
			}
		}
		else
		{
			// Consume the saved entry
			bufPtr = me->m_pSavedData;
			me->m_pSavedData = NULL;
		}

		if (bufPtr != NULL)
		{
			/* unserialize the message */
			serializationManager = getRiDSerializationManager();
			if (serializationManager != NULL)
			{
				m = RiDSerializationManager_unserializeEvent(serializationManager, (gen_ptr) bufPtr);
			}

			RiCQNXOSFreeMem(bufPtr);
		}
	}

	return m;
}

/**************/
RiCBoolean RiCOSMessageQueue_isFull(RiC_CONST_TYPE RiCOSMessageQueue * const me)
{
	struct mq_attr			queueAttr;
	RiCBoolean				status = RiCFALSE;

	if ((me != NULL) && (me->m_hQueue != -1))
	{
		// check if new data is in the queue
		if (mq_getattr(me->m_hQueue, &queueAttr) != -1)
		{
			status = ((queueAttr.mq_curmsgs == me->m_QueueSize) ? RiCTRUE : RiCFALSE);
		}
		else
		{
			#ifdef RID_DEBUG
				RiDReportError("RiCOSMessageQueue_isFull : Failed to get queue attributes");
			#endif
		}
	}

	return status;
}

/**************/
RiCOSResult RiCOSMessageQueue_pend(RiCOSMessageQueue * const me)
{
	char					  *	bufPtr = NULL;
	RiDSerializationManager	  * serializationManager = NULL;
	ssize_t						actualLen = 0;
	RiCOSResult					status = RiCOSFailure;

	if ((me != NULL) && (me->m_hQueue != -1))
	{
		// Check if we already have a buffer saved
		if (me->m_pSavedData != NULL)
		{
			status = RiCOSSuccess;
		}
		else
		{
			// Create a buffer
			bufPtr = (char *) RiCQNXOSAllocMem(QNX_DOX_MSG_LEN);

			if (bufPtr != NULL)
			{
				if ((actualLen = mq_receive(me->m_hQueue, bufPtr, QNX_DOX_MSG_LEN, NULL) ) == -1)
				{
				#ifdef RID_DEBUG
					RiDReportErrorWithErrno("RiCOSMessageQueue_pend : mq_receive failed, returning error ", errno);			
				#endif

					RiCQNXOSFreeMem(bufPtr);
				}
				else
				{
					// Store the received message for the get call
					me->m_pSavedData = bufPtr;

					status = RiCOSSuccess;
				}
			}
			else
			{
				#ifdef RID_DEBUG
					RiDReportErrorWithErrno("RiCOSMessageQueue_pend : RiCQNXOSAllocMem failed, returning error ", errno);			
				#endif
			}
		}
	}

	return status;
}

/**************/
RiCOSResult RiCOSMessageQueue_getMessageList(RiC_CONST_TYPE RiCOSMessageQueue * const me, RiCList * l)
{
	/*currently not supported*/
	return RiCOSFailure;
}

#else /*not distrbuted */

RiCBoolean RiCOSMessageQueue_init(RiCOSMessageQueue * const me, RiC_CONST_TYPE RiCBoolean shouldGrow, RiC_MessageQueueSizeType initSize)
{
	RiCBoolean	status = RiCFALSE;

	if (me != NULL)
	{
		if (initSize < 0)
		{
			initSize = RiCOSDefaultMessageQueueSize;
		}

		(void) RiCQueue_Init(&(me->m_baseRiCQueue), initSize);
		RiCQueue_setFixedSize(&me->m_baseRiCQueue, (RiCBoolean)!shouldGrow);
		(void) RiCOSMutex_init(&(me->m_QueueMutex));
		(void) RiCOSEventFlag_init(&(me->m_QueueEventFlag));

		status = RiCTRUE;
	}
	
	return status;
}

/**************/
void RiCOSMessageQueue_cleanup(RiCOSMessageQueue * const me)
{
	if (me != NULL)
	{
		RiCQueue_Cleanup(&me->m_baseRiCQueue);
		RiCOSMutex_cleanup(&me->m_QueueMutex);
		RiCOSEventFlag_cleanup(&me->m_QueueEventFlag);
	}
}

/**************/
RiCOSMessageQueue * RiCOSMessageQueue_create(RiCBoolean shouldGrow, RiC_MessageQueueSizeType initSize)
{
	RiCOSMessageQueue * me = (RiCOSMessageQueue *) RiCQNXOSAllocMem(sizeof(RiCOSMessageQueue));
	(void) RiCOSMessageQueue_init(me, shouldGrow, initSize);
	return me;
}

/**************/
void RiCOSMessageQueue_destroy(RiCOSMessageQueue * const me)
{
	if (me != NULL)
	{
		RiCOSMessageQueue_cleanup(me);
		RiCQNXOSFreeMem(me);
	}
}

/*lint -save -e534 (Ignoring return value in the mutex lock() and free()) */
/**************/
RiCOSResult RiCOSMessageQueue_put(RiCOSMessageQueue * const me, gen_ptr message, RiC_CONST_TYPE RiCBoolean fromISR)
{
	RiCOSResult	status = RiCOSFailure;

	RiCBoolean result;
	RiCBoolean  wasEmpty;
	if (me != NULL)
	{
		RiCOSMutex_lock(&(me->m_QueueMutex));
		wasEmpty = RiCOSMessageQueue_isEmpty(me);
		result = RiCQueue_push(&(me->m_baseRiCQueue), message);
		if (wasEmpty)
		{
			(void) RiCOSEventFlag_signal(&(me->m_QueueEventFlag));
		}
		RiCOSMutex_free(&(me->m_QueueMutex));

		status = RiCOSSuccess;
	}
	
	return status;
}	/*lint !e715 (Symbol 'fromISR' not referenced) */

/**************/
gen_ptr RiCOSMessageQueue_get(RiCOSMessageQueue * const me)
{
	gen_ptr m = NULL;

	/* safe programming */
	if (me != NULL)
	{
		RiCOSMutex_lock(&(me->m_QueueMutex));
		if(!RiCOSMessageQueue_isEmpty(me))
		{
			m = RiCQueue_pop(&(me->m_baseRiCQueue));
		}
		else
		{
			(void) RiCOSEventFlag_reset(&(me->m_QueueEventFlag));
		}

		RiCOSMutex_free(&(me->m_QueueMutex));
	}

	return m;
}

/**************/
RiCBoolean RiCOSMessageQueue_isFull(RiC_CONST_TYPE RiCOSMessageQueue * const me)
{
	return RiCQueue_isFull(&(me->m_baseRiCQueue));
}

/**************/
RiCOSResult RiCOSMessageQueue_pend(RiCOSMessageQueue * const me)
{
	RiCOSResult	status = RiCOSFailure;

	if (me != NULL)
	{
		if (RiCOSMessageQueue_isEmpty(me))
		{
			status = RiCOSEventFlag_wait(&(me->m_QueueEventFlag), -1);
		}
		else
		{
			status = RiCOSSuccess;
		}
	}

	return status;
}

/**************/
RiCOSResult RiCOSMessageQueue_getMessageList(RiC_CONST_TYPE RiCOSMessageQueue * const me, RiCList * l)
{
	RiCOSResult	status = RiCOSFailure;

	RiCList_removeAll(l);

	if (me != NULL)
	{
		RiCQueue_getQueue(&me->m_baseRiCQueue, l);
		status = RiCOSSuccess;
	}

	return status;
}
#endif

/***************************************************/
/****			OS Semaphore					****/
/***************************************************/
RiCBoolean RiCOSSemaphore_init(RiCOSSemaphore * const me, RiC_CONST_TYPE RiC_SEM_ARGS_TYPE semFlags,
                                RiC_SEM_ARGS_TYPE initialCount,
                                RiC_CONST_TYPE RiC_SEM_ARGS_TYPE maxCount,
                                const RiC_CHAR8 *const name )
{
	RiCBoolean	status = RiCFALSE;

	if (me != NULL)
	{
		if (sem_init(&(me->hSemaphore), (int)semFlags, initialCount) == 0)
		{
			status = RiCTRUE;
		}
	}

	return status;
}

/**************/
void RiCOSSemaphore_cleanup(RiCOSSemaphore * const me)
{
	if (me != NULL) (void) sem_destroy(&(me->hSemaphore));
}

/**************/
RiCOSSemaphore * RiCOSSemaphore_create(RiC_SEM_ARGS_TYPE semFlags,
                                       RiC_SEM_ARGS_TYPE initialCount,
                                       RiC_SEM_ARGS_TYPE maxCount,
                                       const RiC_CHAR8 *const name )
{
	RiCOSSemaphore * me = (RiCOSSemaphore *) RiCQNXOSAllocMem(sizeof(RiCOSSemaphore));
	(void) RiCOSSemaphore_init(me, semFlags, initialCount, maxCount, name);
	return me;
}

/**************/
void RiCOSSemaphore_destroy(RiCOSSemaphore * const me)
{
	if (me != NULL)
	{
		RiCOSSemaphore_cleanup(me);
		RiCQNXOSFreeMem(me);
	}
}

/**************/
RiCOSResult RiCOSSemaphore_signal(RiC_CONST_TYPE RiCOSSemaphore * const me)
{
	return ((sem_post(&(me->hSemaphore)) == 0) ? RiCOSSuccess : RiCOSFailure);
}

/**************/
RiCOSResult RiCOSSemaphore_wait(RiC_CONST_TYPE RiCOSSemaphore *  const me, RiC_CONST_TYPE RiC_TimeOutType timeout)
{
	RiCOSResult	status = RiCOSFailure;

	if (timeout == -1)
	{
		status = ((sem_wait(&(me->hSemaphore)) == 0) ? RiCOSSuccess : RiCOSFailure);
	}
	else
	{
		// POSIX semaphores do not have timeouts.
		// To implement timeouts we loop on a try without wait
		// then sleep 10 ms until either semaphore is open ( ret value is 0)
		// or time is up.
        struct timespec tms;
		if (0 != sem_trywait(&(me->hSemaphore)))
		{
			timeUnit sleepTimeInterval = 10;

			int count = timeout / (int) sleepTimeInterval;
			int i = 0;
			for (i = 1; i < count ; i++)
			{
	      	   	tms.tv_sec = sleepTimeInterval/1000 ;
				tms.tv_nsec = (sleepTimeInterval % 1000)* 1000000;
	           	nanosleep(&tms, NULL);

				if (0 == sem_trywait(&(me->hSemaphore)))
				{
					status = RiCOSSuccess;
					break;
				}
			}
		}
		else
		{
			status = RiCOSSuccess;
		}
	}

	return status;
}



#ifdef _OMINSTRUMENT
#include <omcom/omsdata.h>

#include <stdio.h>

/***************************************************/
/****			OS ConnectionPort				****/
/***************************************************/

/** shared ConnectionPort info **/
typedef struct {
	char * m_Buf;
	int m_BufSize;
} RiCQNXCPCommon;

static RiCQNXCPCommon ConnPortData = { NULL, 0 };
/*
** Private functions
*/
void readFromSockLoop(RiCOSConnectionPort * const me)
{
	char lenStr[MAX_LEN_STR+1];
	int len;
	int rv;

	for (;;)
	{
		rv = RiCOSSocket_receive(&(me->m_Socket),lenStr,MAX_LEN_STR);
		if (rv == -1)
		{
			break;
		}
		lenStr[MAX_LEN_STR] = '\0';

		if (sscanf(lenStr,"%d",&len) == 1)
		{
			if (len > ConnPortData.m_BufSize )
			{
				ConnPortData.m_BufSize = 1000+len;
				if (ConnPortData.m_Buf)
				{
					RiCQNXOSFreeMem(ConnPortData.m_Buf);
				}
				ConnPortData.m_Buf = (char *) RiCQNXOSAllocMem(ConnPortData.m_BufSize);
			}

			if (len == -2)
			{ // Acknowledge message
				RiCOSEventFlag_signal(&(me->m_AckEventFlag));
				continue;
			}

			ConnPortData.m_Buf[len] = '\0';
			rv = RiCOSSocket_receive(&(me->m_Socket),ConnPortData.m_Buf,len);

			if (rv == -1)
			{
				break;
			}
			// len is not used by OMSData but we need to change
			// the interface so we will use the length of the data
			// and not assume that the string is null terminated

			// if socket thread is doing some work that may send
			// messages we do not want to Block the Send by wainting for
			// acknoldegment since the thread cannot handle the acknoledgment
			// ( since the thraed is self locked)
			me->m_ShouldWaitForAck = 0;
			RiCOSEventFlag_signal(&(me->m_AckEventFlag));
			me->m_dispatchfunc(RiCSData_string2RiCSData(ConnPortData.m_Buf));
			me->m_ShouldWaitForAck = 1;
		}
	} //for(;;)
}

/*
// Public function implementation
*/

RiCBoolean RiCOSConnectionPort_init(RiCOSConnectionPort * const me)
{
	RiCBoolean status = RiCFALSE;
	static RiCBoolean bufInitialized = RiCFALSE;

	if (me != NULL)
	{
		me->m_Connected = 0;
		me->m_dispatchfunc = NULL;
		me->hSocketHandleThread = NULL;
		me->m_ShouldWaitForAck = 1;
		me->m_NumberOfMessagesBetweenAck = 0;

		RiCOSEventFlag_init(&(me->m_AckEventFlag));
		RiCOSMutex_init(&(me->m_SendMutex));
		RiCOSSocket_init(&(me->m_Socket));

		status = RiCTRUE;
	}

	return status;
}

/**************/
void RiCOSConnectionPort_cleanup(RiCOSConnectionPort * const me)
{
	if (me != NULL)
	{
		/* close the animation thread */
		if (me->hSocketHandleThread)
		{
			pthread_cancel(me->hSocketHandleThread); 
		}

		me->m_dispatchfunc = NULL;
		me->hSocketHandleThread = NULL;

		RiCOSMutex_cleanup(&me->m_SendMutex);
		RiCOSSocket_cleanup(&me->m_Socket);
		RiCOSEventFlag_cleanup(&me->m_AckEventFlag);


		/*
		// I assume that we will have only one connection port
		// so I can free the data for m_Buf but if it is not the case
		// it does not matter ( the readFromSockLoop will allocate it )
		*/
		if (ConnPortData.m_Buf)
		{
			RiCQNXOSFreeMem(ConnPortData.m_Buf);
			ConnPortData.m_Buf = NULL;
		}
		ConnPortData.m_BufSize = 0;
	}
}

/**************/
RiCOSConnectionPort * RiCOSConnectionPort_create()
{
	RiCOSConnectionPort * me = (RiCOSConnectionPort *) RiCQNXOSAllocMem(sizeof(RiCOSConnectionPort));
	(void) RiCOSConnectionPort_init(me);
	return me;
}

/**************/
void RiCOSConnectionPort_destroy(RiCOSConnectionPort * const me)
{
	if (me != NULL)
	{
		RiCOSConnectionPort_cleanup(me);
		RiCQNXOSFreeMem(me);
	}
}

/**************/
int RiCOSConnectionPort_Connect(RiCOSConnectionPort * const me, const char* const SocketAddress,unsigned int nSocketPort)
{
	RiCOSResult	status = RiCOSFailure;
    pthread_attr_t tthread_attr;

	if (me != NULL)
	{
		if (NULL == me->m_dispatchfunc)
		{
			fprintf(stderr," RiCOSConnectionPort_SetDispatcher should be called before RiCOSConnectionPort_Connect()\n");
		}
		else
		{
			if (0  == me->m_Connected)
			{
				me->m_Connected = RiCOSSocket_createSocket(&(me->m_Socket), SocketAddress, nSocketPort);
			}

			if (0 != me->m_Connected)
			{
				// Connection established
				// invoking thread to recieve messages from the socket
				pthread_attr_init( &tthread_attr );
				pthread_attr_setstacksize( &tthread_attr, (size_t) RiCOSDefaultStackSize );
				pthread_attr_setdetachstate( &tthread_attr, PTHREAD_CREATE_DETACHED);
				pthread_attr_setinheritsched( &tthread_attr, PTHREAD_INHERIT_SCHED );

				if (pthread_create(&(me->hSocketHandleThread), /* Handle */
								   &tthread_attr ,
								   (FormalThrCreateFunc)readFromSockLoop,
								   (void*) me) == EOK)
				{
					status = RiCOSSuccess;
				}
			}
		}
	}

	return status;
}

/**************/
int RiCOSConnectionPort_Send(RiCOSConnectionPort * const me, RiCSData * m)
{
	int status = RiCOSFailure;

	if (me != NULL)
	{
		RiCOSMutex_lock(&me->m_SendMutex);

		if (me->m_Connected)
		{
			char lenStr[MAX_LEN_STR+1];
			sprintf(lenStr,"%d",RiCSData_getLength(m));

			status = RiCOSSocket_send(&me->m_Socket,lenStr,MAX_LEN_STR);
			if (status > 0)
			{
				status = RiCOSSocket_send(&me->m_Socket,RiCSData_getRawData(m),(int) RiCSData_getLength(m));
			}

			/* need to check with Rhapsody */
			if (me->m_ShouldWaitForAck)
			{
				const int maxNumOfMessagesBetweenAck = 127; /* MUST match the number in rhapsody */
				if (maxNumOfMessagesBetweenAck > 0)
				{ /*lint !e774 !e506 () */
					me->m_NumberOfMessagesBetweenAck++;
					if (me->m_NumberOfMessagesBetweenAck >= maxNumOfMessagesBetweenAck)
					{
						me->m_NumberOfMessagesBetweenAck = 0;
						(void) RiCOSEventFlag_wait(&me->m_AckEventFlag, -1);
						(void) RiCOSEventFlag_reset(&me->m_AckEventFlag);
					}
				}
			}

		}
		RiCOSMutex_free(&me->m_SendMutex);

		/* cleanup */
		RiCSData_cleanup(m);
	}

	return status;
}
/*lint -restore (ignoring return value on mutex lock() and free()) */

/**************/
RiCBoolean RiCOSConnectionPort_SetDispatcher(RiCOSConnectionPort * const me, RiCOS_dispatchfunc dispfunc)
{
	RiCBoolean	status = RiCFALSE;

	if (me != NULL)
	{
		me->m_dispatchfunc = dispfunc;
		status = RiCTRUE;
	}

	return status;
}


/***************************************************/
/****					OS Socket				****/
/***************************************************/

#ifndef SOCKET_ERROR
#define SOCKET_ERROR -1
#endif // SOCKET_ERROR

/*
// Private definitions and functions
*/

/*
// Public RiCOSSocket functions (implementation)
*/

RiCBoolean RiCOSSocket_init(RiCOSSocket * const me)
{
	RiCBoolean	status = RiCFALSE;

	if (me != NULL)
	{
		me->theSock = 0;
		status = RiCTRUE;
	}

	return status;
}

/**************/
void RiCOSSocket_cleanup(RiCOSSocket * const me)
{
	if (me != NULL)
	{
		if (me->theSock != 0)
		{
			(void) close(me->theSock);
		}
	}
}

/**************/
RiCOSSocket * RiCOSSocket_create()
{
	RiCOSSocket * me = (RiCOSSocket *) RiCQNXOSAllocMem(sizeof(RiCOSSocket));
	(void) RiCOSSocket_init(me);
	return me;
}

/**************/
void RiCOSSocket_destroy(RiCOSSocket * const me)
{
	if (me == NULL)
	{
		return;
	}

	RiCOSSocket_cleanup(me);
	RiCQNXOSFreeMem(me);
}

/**************/
int RiCOSSocket_createSocket(RiCOSSocket * const me, const char * SocketAddress, unsigned int nSocketPort)
{
	static struct sockaddr_in	addr;
	struct protoent			  *	protocol;
	int							proto;
	struct hostent			  *	host = NULL;
	char					  *	proto_name = "tcp";
	char						hostName[128];
	int							rvStat;
	int							status = RiCOSFailure;

	if (nSocketPort == 0)
	{
		nSocketPort = 6423;		// Default Rhapsody animation port
	}

	addr.sin_family = AF_INET;
	if ((protocol = getprotobyname(proto_name)) == (struct protoent *) 0)
	{
		fprintf(stderr,"Could not get the AF_INET protocol\n");
	}
	else
	{
		proto = protocol->p_proto;

		(void) gethostname(hostName, sizeof(hostName) - 1);
		if ((NULL != SocketAddress) && (strlen(SocketAddress)) != 0)
		{
			if (!strcmp(hostName,SocketAddress))
			{
				SocketAddress = NULL;
			}
			else
			{
				strcpy(hostName,SocketAddress);
				if ((host = gethostbyname(hostName)) == (struct hostent *) 0)
				{
					fprintf(stderr,"Could not get the address of host '%s'\n", hostName);
				}
			}
		}

		addr.sin_port = htons((u_short)nSocketPort);

		if ((NULL == SocketAddress) || (strlen(SocketAddress) == 0))
		{
			addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
		}
		else if(host)
		{
			addr.sin_addr.s_addr = *((RiC_INT32 *) host->h_addr);
		}

		if ((me->theSock = socket(AF_INET, SOCK_STREAM, proto)) == -1)
		{
			fprintf(stderr,"Could not create socket\n");
			me->theSock = 0;
		}
		else
		{
			/*lint -save -e740 (Unusual pointer cast) */
			while ((rvStat = connect(me->theSock, (struct sockaddr *) &addr, sizeof(addr))) ==
				SOCKET_ERROR && (errno == EINTR))
				;
			/*lint -restore */

			if (SOCKET_ERROR == rvStat)
			{
				fprintf(stderr, "Could not connect to server at %s port %d\n Error No. : %d\n",
					hostName, (int)nSocketPort, errno);
			}
			else
			{
				status = RiCOSSuccess;
			}
		}
	}

	return status;
}

/**************/
int RiCOSSocket_send(RiCOSSocket * const me, const char * buf, int bufLen)
{
	int bytes_writ = 0;
	int n;

	if (me != NULL)
	{
		while (bytes_writ < bufLen)
		{
			n = send(me->theSock, buf + bytes_writ, bufLen - bytes_writ,0);
			if (SOCKET_ERROR == n)
			{
				if (errno == EINTR)
				{
					continue;
				}
				else
				{
					bytes_writ = -1;
					break;
				}
			}

			bytes_writ += n;
		}
	}

	return bytes_writ;
}

/**************/
int RiCOSSocket_receive(RiCOSSocket * const me, char * buf, int bufLen)
{
	int bytes_read = 0;
	int n;

	if (me != NULL)
	{
		while (bytes_read < bufLen)
		{
			n = recv(me->theSock, buf + bytes_read, bufLen - bytes_read,0);
			if (SOCKET_ERROR == n)
			{
				if (errno == EINTR)
				{
					continue;
				}
				else
				{
					bytes_read = -1;
					break;
				}
			}
			bytes_read += n;
		}
	}

	return bytes_read;
}

#endif	/* _OMINSTRUMENT */


/*
// $Log:  $
*/
