/**********************************************************************
 * Copyright (c) 2005, 2009 IBM Corporation and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * $Id: RAComm.c,v 1.17 2009/08/26 14:59:53 jwest Exp $
 *
 * Contributors:
 * IBM - Initial API and implementation
 * Spundun Bhatt (spundun@gmail.com), with the support and encouragement of the University of Southern California Information Sciences Institute Distributed Scalable Systems Division.
 **********************************************************************/

#include <stddef.h>
#include "RAComm.h"
#include "RAError.h"



#ifdef _WIN32
 #include <rpc.h>
#else
	#include <langinfo.h>
	#include <locale.h>
	#include <iconv.h>
	#include <string.h>
	#include <unistd.h>

 #include <sys/time.h>
 #ifndef __OS400__
   #include <sys/timeb.h>
 #else
   #include <qp0wpid.h>
 #endif
 
 #include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <dirent.h>
#endif

#ifdef _AIX
 #include <sys/atomic_op.h>       /* compare_and_swap */
#elif MVS                        /* 174190 */
 #define _inline
 #include <unistd.h>
#elif __OS400__
 #include <iconv.h> /* 236501 */
 #include <mih/cmpswp.h>	       /* cmpswp	      */
 #include <pointer.h>                /* for _SYSPTR   Bugzilla #57112 - adding LOADLIBRARY support for OS400*/
 #include <mih/rslvsp.h>           /* rslvsp(),  Bugzilla #57112 - adding LOADLIBRARY support for OS400 */
 #include <qleawi.h>                 /* QleActBndPgm(),  QleGetExp()  Bugzilla #57112 */
 #include <qusec.h>                  /* Qus_EC_t   Bugzilla #57112 */
#elif defined __linux__
	#define _inline inline
	#if defined __i386__ && !defined(USE_PTHREAD_ATOMICS)

         /* the following pre-processor handles various versions of */
         /*    asm/system.h and asm/bitops.h                        */
         #include <asm/bitops.h>
         #ifndef  LOCK_PREFIX
             #ifdef CONFIG_SMP
                #define LOCK_PREFIX "lock ; "
             #else
                #define LOCK_PREFIX ""
             #endif
         #endif

         #include <asm/system.h>

	#elif defined __i386__ && defined(USE_PTHREAD_ATOMICS)

		#define _NO_ATOMIC_CAS 1

	#elif defined __s390__
		#if !(defined(USE_GCC_ATOMICS))
			#include <asm/atomic.h>
		#else
			// Added code below to the elif for 390 (tptp/atomic_s390.h)
			// problem when including asm/atomic.h - sl
			#ifndef atomic_compare_and_swap
			#define atomic_compare_and_swap(oldval,newval,ptr) \
				!__sync_bool_compare_and_swap(ptr,oldval,newval)
			#endif
		#endif
	#elif defined __powerpc__
		#include <asm/system.h>
		#include <asm/atomic.h>
		#define _NO_ATOMIC_CAS 1
	#endif
#elif _SOLARIS
 #define _inline
 #define _NO_ATOMIC_CAS 1
#elif __APPLE__
 #define _inline
 #define _NO_ATOMIC_CAS 1
#elif _HPUX
 #include <unistd.h>
 #define _inline
 #define _NO_ATOMIC_CAS 1
#endif

#if defined(MVS) || defined(_AIX)
#include <sys/resource.h>
#endif


/*RKD:  On platforms where we don't have *good* atomic operations for compare
        and swap we will use the pthread mutextes.  This is atomic
		only in the current process and cannot be used across multiple processes.
		Furthermore, the element being modified cannot be by some arbitrary
		instuction.  It must always be modified using the compare and swap
		function or else it is not safe!
*/
#ifdef _NO_ATOMIC_CAS
#include <pthread.h>
pthread_mutex_t _cas_mutex=PTHREAD_MUTEX_INITIALIZER;
#endif

#ifdef _DEBUG2
#include <stdio.h>
#endif


/**
  * Globals
  */
/* Last error holder */
static ra_uint_t _raLastErrorMajor=0;
static ra_uint_t _raLastErrorMinor=0;


/**
  * Function prototypes
  */
static BOOL validateControlMessage(unsigned char *msg,
								   int length);


static unsigned char* copyRAUINTToBuffer(unsigned char *buffer,
							   ra_uint_t uintData) {
	buffer[0]=(unsigned char)(uintData>>24 & 0x000000ff);
	buffer[1]=(unsigned char)(uintData>>16 & 0x000000ff);
	buffer[2]=(unsigned char)(uintData>>8  & 0x000000ff);
	buffer[3]=(unsigned char)uintData;
	return &buffer[4];
}

static unsigned char* readRAUINTFromBuffer(unsigned char *buffer, ra_uint_t *uint) {
	*uint=((ra_uint_t)(buffer[0]<<24)
					  |(ra_uint_t)(buffer[1]<<16)
					  |(ra_uint_t)(buffer[2]<<8)
					  | buffer[3]);
	return &buffer[sizeof(ra_uint_t)];
}

/* 190770 - Note that for 390, the buffer to copy into must be at least one byte larger
            than the data in stringData to accomodate a terminating null character
            required for EBCDIC to ASCII conversion */
static unsigned char* copyRASTRINGToBuffer(unsigned char *buffer, ra_string_t *stringData) {

	ra_uint_t padding = 0;
	ra_uint_t utf8Len = 0;
	ra_uint_t nativeLen = 0;
	char* utf8Buffer = 0;
	char* nativeBuffer = 0;
#if _DEBUG2
	char* dbgBuffer = 0;
#endif

	nativeLen = stringData->length;
	nativeBuffer = stringData->data;

	if(nativeLen == 0) {
		copyRAUINTToBuffer(buffer, 0);
		return &buffer[sizeof(ra_uint_t)];
	}
	else {
		utf8Len = native2unicode(&utf8Buffer, nativeBuffer, nativeLen);

		if(utf8Len && utf8Buffer) {
			padding = 4 - (utf8Len)%4;
			if(padding == 4) {
				padding = 0;
			}

			copyRAUINTToBuffer(buffer, utf8Len);
			memcpy(&buffer[4], utf8Buffer, utf8Len);
			BZERO(&buffer[4 + utf8Len], padding); /* Fill the rest of the bytes with zeros */

		}
		else {
			copyRAUINTToBuffer(buffer, 0);
		}

#if _DEBUG2
	dbgBuffer = (char*)ra_malloc(sizeof(char*) * (utf8Len + 1));
	memcpy(dbgBuffer, utf8Buffer, utf8Len);
	dbgBuffer[utf8Len] = '\0';
	printf("DEBUG: (Native->UTF8) \"%s\" -> \"%s\"\n", nativeBuffer, dbgBuffer);
	ra_free(dbgBuffer);
#endif

		if(utf8Buffer != 0) {
			ra_free(utf8Buffer);
		}

		return &buffer[sizeof(ra_uint_t) + utf8Len + padding];
	}
}

static unsigned char* copyRABinaryArrayToBuffer(unsigned char *buffer, ra_string_t *binaryData) {
	ra_uint_t padding=4-(binaryData->length)%4;

	if(padding==4) {
		padding=0;
	}

	copyRAUINTToBuffer(buffer, binaryData->length);
	memcpy(&buffer[4], binaryData->data, binaryData->length);
	BZERO(&buffer[4 + binaryData->length], padding); /* Fill the rest of the bytes with zeros */

	return &buffer[sizeof(ra_uint_t)+binaryData->length+padding];
}

static unsigned char* readRASTRINGFromBuffer(unsigned char *buffer, ra_string_t *newString) {
	ra_uint_t padding = 0;
	ra_uint_t utf8Len = 0;
	ra_uint_t nativeLen = 0;
	char* utf8Buffer = 0;
	char* nativeBuffer = 0;

	readRAUINTFromBuffer(buffer, &utf8Len);

	if(utf8Len == 0) {
		newString->data = (char*)ra_malloc(sizeof(char));
		newString->data[0] = '\0';
		newString->length = 0;

		return &buffer[sizeof(ra_uint_t)];
	}
	else {
		utf8Buffer = (char*)ra_malloc(sizeof(char) * (utf8Len + 1));
		BZERO(utf8Buffer, utf8Len + 1);
		memcpy(utf8Buffer, &buffer[4], utf8Len); /* read the bytes from buffer */
		utf8Buffer[utf8Len] = '\0';

		/* Convert the value from UTF-8 to native encoding */
		nativeLen = unicode2native(&nativeBuffer, utf8Buffer, utf8Len);

		if(nativeLen && nativeBuffer) {
			newString->data = (char*)ra_malloc(sizeof(char) * (nativeLen + 1));
			BZERO(newString->data, nativeLen + 1);
			memcpy(newString->data, nativeBuffer, nativeLen);
			newString->length = nativeLen;
		}
		else {
			newString->data = (char*)ra_malloc(sizeof(char));
			newString->data[0] = '\0';
			newString->length = 0;
		}

#if _DEBUG2
	printf("DEBUG: (UTF8->Native) \"%s\" -> \"%s\"\n", utf8Buffer, newString->data);
#endif

		ra_free(utf8Buffer);
		if(nativeBuffer != 0) {
			ra_free(nativeBuffer);
		}

		padding = 4 - (utf8Len) % 4;
		if(padding == 4) {
			padding = 0;
		}

		return &buffer[sizeof(ra_uint_t) + utf8Len + padding];
	}
}

static unsigned char* readRABinaryArrayFromBuffer(unsigned char *buffer,
											      ra_string_t *newArray) {
	ra_uint_t padding;
	readRAUINTFromBuffer(buffer, &newArray->length);
	newArray->data=(char*)ra_malloc(newArray->length+1);
	memcpy(newArray->data, &buffer[4], newArray->length);
	newArray->data[newArray->length]='\0';
	padding=4-(newArray->length)%4;
	if(padding==4) {
		padding=0;
	}

	
	return &buffer[sizeof(ra_uint_t)+newArray->length+padding];
}


static int determineRASTRINGSize(ra_string_t *rastring) {
	ra_uint_t padding;
	char* utf8Buffer = 0;
	ra_uint_t utf8Len;

	/* The NULL string is sizeof(ra_uint_t) long */
	if(rastring == NULL) {
		return sizeof(ra_uint_t);
	}
	else if((rastring->length == 0) || (rastring->data == NULL)) {
		/* NULL string as well */
		return sizeof(ra_uint_t);
	}

	utf8Len = native2unicode(&utf8Buffer, rastring->data, rastring->length);

	padding=4 - (utf8Len)%4;
	if(padding==4) {
		padding=0;
	}

	if(utf8Buffer != 0) {
		ra_free(utf8Buffer);
	}

	return sizeof(ra_uint_t) + utf8Len + padding;
}

/* Bug 73074 - Binary Custom Command does not need conversion */
static int determineRABinaryArraySize(ra_string_t *rastring) {
	ra_uint_t padding;

	/* The NULL string is sizeof(ra_uint_t) long */
	if(rastring == NULL) {
		return sizeof(ra_uint_t);
	}
	else if(rastring->data == NULL) {
		/* NULL string as well */
		return sizeof(ra_uint_t);
	}

	padding = 4 - (rastring->length)%4;
	if(padding==4) {
		padding=0;
	}

	return sizeof(ra_uint_t) + rastring->length + padding;
}

/* 199740 begin */
#ifdef _WIN32
/** DISABLE_ALL_SECURITY_OF_KERNAL_OBJECT *************************************
  * The intention of this function is to take a handle to a kernal object and
  * disable all the security on the object, hense allowing access to the object
  * by anyone/everyone.  Once the entire security package is complete this
  * function should be removed and proper access lists should be created.
  * @param  object - the OS specific handle to the kernal object to modify.
  * @returns  TRUE - the security modification was successful.
  *          FALSE - failed, call ra_getLastErrorMajor/Minor to get details.
  */
BOOL disableAllSecurityOfKernalObject(RA_HANDLE object) {
	PSECURITY_DESCRIPTOR objSD;

	/* Allocate the memory for the security descriptor and initialize it */
	if (!(objSD=( PSECURITY_DESCRIPTOR)ra_malloc(SECURITY_DESCRIPTOR_MIN_LENGTH))) {
		ra_setLastError(SECURITY_MODIFICATION_ERROR, GetLastError());
		return FALSE;
	}
	if (!InitializeSecurityDescriptor (objSD, SECURITY_DESCRIPTOR_REVISION)) {
		ra_free(objSD);
		ra_setLastError(SECURITY_MODIFICATION_ERROR, GetLastError());
		return FALSE;
	}

	/* Create a NULL Discretionary ACL for the object */
	if(!SetSecurityDescriptorDacl(objSD,
								  TRUE,
								  (PACL)NULL,
								  FALSE)) {
		ra_free(objSD);
		ra_setLastError(SECURITY_MODIFICATION_ERROR, GetLastError());
		return FALSE;
	}

	/* Set the Descretionary ACL security for the  kernal object */
	if(!SetKernelObjectSecurity(object,
								DACL_SECURITY_INFORMATION,
								objSD)) {
		ra_free(objSD);
		ra_setLastError(SECURITY_MODIFICATION_ERROR, GetLastError());
		return FALSE;
	}

	/* ra_free the resources allocated and return */
	ra_free(objSD);
	return TRUE;
}

#else

BOOL disableAllSecurityOfKernalObject(RA_HANDLE object) {
	return TRUE ;
}

#endif
/* 199740 end */


/** CREATE_MESSAGE  ***********************************************************
  * Allocates the memory for a message and loads it with the specified type and
  * ticket.  In order to ra_free the memory used for this message use ra_destroyMessage()
  * @param  type  - the type of message, be it an RA_ACKNOWLEDGEMENT_MESSAGE
  *                 or a RA_CONTROL_MESSAGE.
  * @param ticket - the ticket number for this message. If this is an
  *                 RA_ACKNOWLEDGEMENT_MESSAGE this should be the ticket of the
  *                 corresponding RA_CONTROL_MESSAGE.
  * @returns !NULL - the address of the newley allocated message.
  *           NULL - inappropriate message type.
  */
ra_message_t* ra_createMessage(ra_uint_t type,
							   ra_uint_t ticket) {
	ra_message_t *message;
	if(type==RA_ACKNOWLEDGEMENT_MESSAGE) {
		message=(ra_message_t*)ra_malloc(sizeof(ra_message_t));
		message->ticket=ticket;
		message->type=type;
		return message;
	}
	else if (type==RA_CONTROL_MESSAGE) {
		message=(ra_message_t*)ra_malloc(sizeof(ra_message_t));
		message->ticket=ticket;
		message->type=type;
		message->length=5*sizeof(ra_uint_t);  /* Initial length with no key or commands */
		message->key.length=0;
		message->key.data=NULL;
		message->commands.head=message->commands.tail=NULL;
		message->commands.count=0;
		return message;
	}
	return NULL;

}

/** DESTROY_MESSAGE  **********************************************************
  * ra_free's all the memory currenltly held by a message and it's associated commands.
  * @param  message - the message to ra_free all the memory of.
  * @param deppra_free - Control messages consist of a list of ra_command_t stuctures
  *                   that are maintained within containers, if deepra_free is true,
  *                   the actual commands are deleted along with the containers.  If
  *                   deepra_free is false, only the containers are deleted.  This is
  *                   usefull for occasions when commands are copied from one message
  *                   to another without a depp copy.
  */
void ra_destroyMessage(ra_message_t *message,
					   BOOL deepFree) {
	ra_command_list_node_t *currentNode;
	ra_command_t *currentCommand;
	if(message->type == RA_ACKNOWLEDGEMENT_MESSAGE) {
		ra_free(message);
		return;
	}

	if (message->key.length > 0) {
		ra_free(message->key.data);
	}

	currentNode=message->commands.head;
	while (currentNode != NULL) {
		ra_command_list_node_t *temp;
		currentCommand=currentNode->command;
		/* Only delete the command data if asked to and if there is something to delete */
		if(deepFree && currentCommand!=NULL) {
			switch(currentCommand->tag) {
				ra_uint_t i;
			case RA_AUTHENTICATE:
				ra_free(currentCommand->info.authenticate.user.data);
				currentCommand->info.authenticate.user.data=NULL;
				ra_free(currentCommand->info.authenticate.passwd.data);
				currentCommand->info.authenticate.passwd.data=NULL;
				break;
			case RA_AUTHENTICATION_SUCCESSFUL:
				ra_free(currentCommand->info.authenticate_successful.key.data);
				currentCommand->info.authenticate_successful.key.data=NULL;
				break;
			case RA_AUTHENTICATION_FAILED:
				break;
            case RA_SERVER_SECURITY_REQUIREMENTS:
                break;
			case RA_LAUNCH_PROCESS:
				ra_free(currentCommand->info.launch_process.executable.data);
				currentCommand->info.launch_process.executable.data=NULL;
				ra_free(currentCommand->info.launch_process.arguments.data);
				currentCommand->info.launch_process.arguments.data=NULL;
				ra_free(currentCommand->info.launch_process.location.data);
				currentCommand->info.launch_process.location.data=NULL;
				for(i=0; i<currentCommand->info.launch_process.environment.length; i++) {
					ra_free(((ra_string_t*)(currentCommand->info.launch_process.environment.data[i]))->data);
					((ra_string_t*)(currentCommand->info.launch_process.environment.data[i]))->data=NULL;
					ra_free(((ra_string_t*)(currentCommand->info.launch_process.environment.data[i])));
					currentCommand->info.launch_process.environment.data[i]=NULL;
				}
				for(i=0; i<currentCommand->info.launch_process.agents.length; i++) {
					ra_free(((ra_string_t*)(currentCommand->info.launch_process.agents.data[i]))->data);
					((ra_string_t*)(currentCommand->info.launch_process.agents.data[i]))->data=NULL;
					ra_free(((ra_string_t*)(currentCommand->info.launch_process.agents.data[i])));
					currentCommand->info.launch_process.agents.data[i]=NULL;
				}
				break;
			case RA_PROCESS_LAUNCHED:
				ra_free(currentCommand->info.process_launched.executable.data);
				currentCommand->info.process_launched.executable.data=NULL;
				ra_free(currentCommand->info.process_launched.arguments.data);
				currentCommand->info.process_launched.arguments.data=NULL;
				ra_free(currentCommand->info.process_launched.processUUID.data);
				currentCommand->info.process_launched.processUUID.data=NULL;
				for(i=0; i<currentCommand->info.process_launched.environment.length; i++) {
					ra_free(((ra_string_t*)(currentCommand->info.process_launched.environment.data[i]))->data);
					((ra_string_t*)(currentCommand->info.process_launched.environment.data[i]))->data=NULL;
					ra_free(((ra_string_t*)(currentCommand->info.process_launched.environment.data[i])));
					currentCommand->info.process_launched.environment.data[i]=NULL;
				}
				break;
			case RA_QUERY_PROCESS_LIST:
				break;
			case RA_PROCESS_LIST:
				for(i=0; i<currentCommand->info.registered_process_list.processes.length; i++) {
					ra_free(((ra_uint_t*)currentCommand->info.registered_process_list.processes.data[i]));
					currentCommand->info.registered_process_list.processes.data[i]=NULL;
				}
				break;
			case RA_QUERY_AGENT_LIST:
			case RA_KILL_PROCESS:
			case RA_PROCESS_EXITED:
				break;
			case RA_AGENT_LIST:
				ra_free(currentCommand->info.registered_agents_list.executable.data);
				currentCommand->info.registered_agents_list.executable.data=NULL;
				for(i=0; i<currentCommand->info.registered_agents_list.agents.length; i++) {
					ra_free(currentCommand->info.registered_agents_list.agents.data[i]);
					currentCommand->info.registered_agents_list.agents.data[i]=NULL;
				}
				break;
			case RA_REGISTER_AGENT_NOTIFICATION:
			case RA_QUERY_AGENT_DETAILS:
				ra_free(currentCommand->info.register_agent_notification.agent.data);
				currentCommand->info.register_agent_notification.agent.data=NULL;
				break;
			case RA_ATTACH_TO_AGENT:
			case RA_DETACH_FROM_AGENT:
			case RA_START_MONITORING_AGENT_REMOTE:
			case RA_STOP_MONITORING_AGENT:
			case RA_AGENT_QUERY_STATE: /* Bug 54376 */
			case RA_AGENT_ATTACHED: /* Bug 54376 */
			case RA_AGENT_DETACHED: /* Bug 54376 */
				ra_free(currentCommand->info.attach.agent.data);
				currentCommand->info.attach.agent.data=NULL;
				break;
			case RA_ERROR_STRING:
				ra_free(currentCommand->info.error_string.agent.data);
				currentCommand->info.error_string.agent.data=NULL;
				ra_free(currentCommand->info.error_string.messageId.data);
				currentCommand->info.error_string.messageId.data=NULL;
				ra_free(currentCommand->info.error_string.message.data);
				currentCommand->info.error_string.message.data=NULL;
				break;
			case RA_START_MONITORING_AGENT_LOCAL:
				ra_free(currentCommand->info.start_monitor_local.agent.data);
				currentCommand->info.start_monitor_local.agent.data=NULL;
				ra_free(currentCommand->info.start_monitor_local.file.data);
				currentCommand->info.start_monitor_local.file.data=NULL;
				break;
			case RA_SET_NAME_VALUE_PAIR:
				ra_free(currentCommand->info.set_nv_pair.agent.data);
				currentCommand->info.set_nv_pair.agent.data=NULL;
				ra_free(currentCommand->info.set_nv_pair.type.data);
				currentCommand->info.set_nv_pair.type.data=NULL;
				ra_free(currentCommand->info.set_nv_pair.name.data);
				currentCommand->info.set_nv_pair.name.data=NULL;
				ra_free(currentCommand->info.set_nv_pair.value.data);
				currentCommand->info.set_nv_pair.value.data=NULL;
				break;
			case RA_CUSTOM_COMMAND:
            case RA_BINARY_CUSTOM_COMMAND:
				ra_free(currentCommand->info.custom_command.agent.data);
				currentCommand->info.custom_command.agent.data=NULL;
				ra_free(currentCommand->info.custom_command.message.data);
				currentCommand->info.custom_command.message.data=NULL;
				break;
			case RA_AGENT_ACTIVE:
			case RA_AGENT_INACTIVE:
			case RA_AGENT_DETAILS:
				ra_free(currentCommand->info.agent_active.agent.data);
				currentCommand->info.agent_active.agent.data=NULL;
				ra_free(currentCommand->info.agent_active.agentUUID.data);
				currentCommand->info.agent_active.agentUUID.data=NULL;
				ra_free(currentCommand->info.agent_active.processUUID.data);
				currentCommand->info.agent_active.processUUID.data=NULL;
				ra_free(currentCommand->info.agent_active.agentType.data);
				currentCommand->info.agent_active.agentType.data=NULL;
				break;
			case RA_AGENT_SCOPING_INFORMATION:
				ra_free(currentCommand->info.agent_scoping_information.agentUUID.data);
				currentCommand->info.agent_scoping_information.agentUUID.data=NULL;
				ra_free(currentCommand->info.agent_scoping_information.processUUID.data);
				currentCommand->info.agent_scoping_information.processUUID.data=NULL;
				ra_free(currentCommand->info.agent_scoping_information.agentType.data);
				currentCommand->info.agent_scoping_information.agentType.data=NULL;
				ra_free(currentCommand->info.agent_scoping_information.nodeUUID.data);
				currentCommand->info.agent_scoping_information.nodeUUID.data=NULL;
				break;
			case RA_AGENT_CONFIGURATION:
				ra_free(currentCommand->info.agent_configuration.agentUUID.data);
				currentCommand->info.agent_configuration.agentUUID.data=NULL;
				ra_free(currentCommand->info.agent_configuration.processUUID.data);
				currentCommand->info.agent_configuration.processUUID.data=NULL;
				ra_free(currentCommand->info.agent_configuration.agentType.data);
				currentCommand->info.agent_configuration.agentType.data=NULL;
				ra_free(currentCommand->info.agent_configuration.nodeUUID.data);
				currentCommand->info.agent_configuration.nodeUUID.data=NULL;
				for(i=0; i<currentCommand->info.agent_configuration.configuration.length; i++) {
					ra_agentConfigEntry_t *entry=((ra_agentConfigEntry_t*)(currentCommand->info.agent_configuration.configuration.data[i]));
					ra_free(entry->type.data);
					entry->type.data=NULL;
					ra_free(entry->name.data);
					entry->name.data=NULL;
					ra_free(entry->value.data);
					entry->value.data=NULL;
				}
				break;
			case RA_AGENT_CONTROLER_AVAILABLE:
			case RA_AGENT_CONTROLER_UNAVAILABLE:
				ra_free(currentCommand->info.agentName.data);
				currentCommand->info.agentName.data=NULL;
				break;
			case RA_AGENT_REQUEST_MONITOR:
			case RA_CONTROLLER_REQUEST_MONITOR:
			case RA_PEER_UNREACHABLE:
			case RA_AGENT_REQUEST_MONITOR_PORT: /* Bug 77768 */
			case RA_CONTROLLER_REQUEST_MONITOR_PORT: /* Bug 77768 */
				ra_free(currentCommand->info.agent_request_monitor.agent.data);
				currentCommand->info.agent_request_monitor.agent.data=NULL;
				ra_free(currentCommand->info.agent_request_monitor.node.data);
				currentCommand->info.agent_request_monitor.node.data=NULL;
				ra_free(currentCommand->info.agent_request_monitor.peerAgent.data);
				currentCommand->info.agent_request_monitor.peerAgent.data=NULL;
				ra_free(currentCommand->info.agent_request_monitor.peerNode.data);
				currentCommand->info.agent_request_monitor.peerNode.data=NULL;
				break;
			case RA_GET_PROPERTY_LIST:
				ra_free(currentCommand->info.query_property_list.name.data);
				currentCommand->info.query_property_list.name.data = NULL;
				ra_free(currentCommand->info.query_property_list.type.data);
				currentCommand->info.query_property_list.type.data = NULL;
				ra_free(currentCommand->info.query_property_list.agentUUID.data);
				currentCommand->info.query_property_list.agentUUID.data = NULL;
				break;
			case RA_PROPERTY_LIST:
				/* Names, Types, Values */
				for(i = 0; i < currentCommand->info.property_list.entries.length; i++) {
					ra_free(((ra_agentConfigEntry_t**)currentCommand->info.property_list.entries.data)[i]->name.data);
					ra_free(((ra_agentConfigEntry_t**)currentCommand->info.property_list.entries.data)[i]->type.data);
					ra_free(((ra_agentConfigEntry_t**)currentCommand->info.property_list.entries.data)[i]->value.data);
				}
				if(currentCommand->info.property_list.entries.length > 0) {
					ra_free((ra_agentConfigEntry_t**)currentCommand->info.property_list.entries.data);
				}
				break;
			/** Added by Giridhar.S on 13/2/04 **/
			case RA_MANAGE_FILE:
				ra_free(currentCommand->info.manage_file.filename.data);
				currentCommand->info.manage_file.filename.data=NULL;
				break;
			case RA_RESOURCE_LOCATION:
				ra_free(currentCommand->info.resource_location.jobKey.data);
				currentCommand->info.resource_location.jobKey.data=NULL;
				break;

			}
			ra_free(currentCommand);
			currentNode->command=NULL;
		}
		temp=currentNode;
		currentNode=currentNode->next;
		ra_free(temp);
		temp=NULL;
	}
	ra_free(message);
	message=NULL;
}

/** ADD_COMMAND_TO_MESSAGE  ***************************************************
  * Adds a command to the message command list.
  * @param  message - the previously allocated message to append the command to.
  * @param  command - the command to append to the message command list.  If this
  *                   is NULL, the memory for the command is allocated.
  * @retruns        - a pointer to the appended command.
  */
ra_command_t* ra_addCommandToMessage(ra_message_t *message,
									 ra_command_t *command) {
	ra_command_list_node_t *newNode;
	ra_command_t *newCommand=command;
	newNode=(ra_command_list_node_t*)ra_malloc(sizeof(ra_command_list_node_t));

	if(newCommand==NULL) {
		newCommand=(ra_command_t*)ra_malloc(sizeof(ra_command_t));
	}

	/* If there is no message just return the command */
	if(!message) {
		return newCommand;
	}

	/* Insert the command in message_list */
	newNode->command=newCommand;
	newNode->next=NULL;
	newNode->previous=message->commands.tail;
	message->commands.tail=newNode;

	/* If this not the first entry we must set the link in the previous tail */
	if(newNode->previous) {
		newNode->previous->next=newNode;
	}
	else {
		message->commands.head=newNode;
	}
	message->commands.count++;

	return newCommand;
}

/** DETERMINE_MESSAGE_LENGTH  ***************************************************
  * DEtermines the size buffer required to fit the information that is stored in
  * the specified ra_message_t structure.
  * @param  message - the message to determine the length of.
  * @returns     >0 - the size of buffser required.
  *               0 - the message parameter was NULL
  */
int ra_determineMessageLength(ra_message_t *message) {
	if(!message) {
		return 0;
	}

	/* Acknowledgement messages are all the same length */
	if(message->type == RA_ACKNOWLEDGEMENT_MESSAGE) {
		return 4*sizeof(ra_uint_t);
	}

	/* Control messages */
	if(message->type == RA_CONTROL_MESSAGE) {
		ra_command_list_node_t *current;
		int currentSize=5*sizeof(ra_uint_t);
		/* Add the key */
		currentSize+=determineRASTRINGSize(&message->key);
		/* add the count */
		currentSize+=sizeof(ra_uint_t);


		/* Walk the command list determining the length of each command */
		current=message->commands.head;
		while(current != NULL) {
			/* Add the tag size */
			ra_command_t *command=current->command;
			currentSize+=sizeof(ra_uint_t);
			switch(command->tag) {
				unsigned int i;
			case RA_AUTHENTICATE:
				currentSize+=determineRASTRINGSize(&command->info.authenticate.user);
				currentSize+=determineRASTRINGSize(&command->info.authenticate.passwd);
				break;
			case RA_AUTHENTICATION_SUCCESSFUL:
				currentSize+=determineRASTRINGSize(&command->info.authenticate_successful.key);
				break;
			case RA_AUTHENTICATION_FAILED:
				currentSize+=sizeof(ra_uint_t);
				break;
            case RA_SERVER_SECURITY_REQUIREMENTS:
                currentSize+=2*sizeof(ra_uint_t);
                break;
			case RA_LAUNCH_PROCESS:
				currentSize+=4*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.launch_process.executable);
				currentSize+=determineRASTRINGSize(&command->info.launch_process.arguments);
				currentSize+=determineRASTRINGSize(&command->info.launch_process.location);
				currentSize+=sizeof(ra_uint_t);
				if(command->info.launch_process.environment.length) {
					for(i=0; i<command->info.launch_process.environment.length; i++) {
						currentSize+=determineRASTRINGSize(((ra_string_t*)((ra_string_t**)command->info.launch_process.environment.data)[i]));
					}
				}
				currentSize+=sizeof(ra_uint_t);
				if(command->info.launch_process.agents.length) {
					for(i=0; i<command->info.launch_process.agents.length; i++) {
						currentSize+=determineRASTRINGSize(((ra_string_t*)((ra_string_t**)command->info.launch_process.agents.data)[i]));
					}
				}
				break;
			case RA_PROCESS_LAUNCHED:
				currentSize+=2*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.process_launched.executable);
				currentSize+=determineRASTRINGSize(&command->info.process_launched.arguments);
				currentSize+=determineRASTRINGSize(&command->info.process_launched.processUUID);
				currentSize+=sizeof(ra_uint_t);
				if(command->info.process_launched.environment.length) {
					for(i=0; i<command->info.process_launched.environment.length; i++) {
						currentSize+=determineRASTRINGSize(((ra_string_t*)((ra_string_t**)command->info.process_launched.environment.data)[i]));
					}
				}
				break;
			case RA_REGISTER_AGENT_NOTIFICATION:
			case RA_QUERY_AGENT_DETAILS:
				currentSize+=2*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.register_agent_notification.agent);
				break;
			case RA_QUERY_PROCESS_LIST:
				currentSize+=sizeof(ra_uint_t);
				break;
			case RA_PROCESS_LIST:
				currentSize+=sizeof(ra_uint_t);
				currentSize+=sizeof(ra_uint_t) * (1+command->info.registered_process_list.processes.length);
				break;
			case RA_QUERY_AGENT_LIST:
			case RA_KILL_PROCESS:
			case RA_PROCESS_EXITED:
				currentSize+=2*sizeof(ra_uint_t);
				break;
			case RA_AGENT_LIST:
				currentSize+=3*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.registered_agents_list.executable);
				if(command->info.registered_agents_list.agents.length) {
					for(i=0; i<command->info.registered_agents_list.agents.length; i++) {
						currentSize+=determineRASTRINGSize(((ra_string_t*)((ra_string_t**)command->info.registered_agents_list.agents.data)[i]));
					}
				}
				break;
			case RA_ATTACH_TO_AGENT:
			case RA_DETACH_FROM_AGENT:
			case RA_STOP_MONITORING_AGENT:
			case RA_AGENT_QUERY_STATE: /* Bug 54376 */
			case RA_AGENT_ATTACHED: /* Bug 54376 */
			case RA_AGENT_DETACHED: /* Bug 54376 */
				currentSize+=2*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.attach.agent);
				break;
			case RA_ERROR_STRING:
				currentSize+=3*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.error_string.agent);
				currentSize+=determineRASTRINGSize(&command->info.error_string.messageId);
				currentSize+=determineRASTRINGSize(&command->info.error_string.message);
				break;
			case RA_START_MONITORING_AGENT_REMOTE:
				currentSize+=4*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.start_monitor_remote.agent);
				break;
			case RA_START_MONITORING_AGENT_LOCAL:
				currentSize+=2*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.start_monitor_local.agent);
				currentSize+=determineRASTRINGSize(&command->info.start_monitor_local.file);
				break;
			case RA_SET_NAME_VALUE_PAIR:
				currentSize+=2*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.set_nv_pair.agent);
				currentSize+=determineRASTRINGSize(&command->info.set_nv_pair.type);
				currentSize+=determineRASTRINGSize(&command->info.set_nv_pair.name);
				currentSize+=determineRASTRINGSize(&command->info.set_nv_pair.value);
				break;
			case RA_CUSTOM_COMMAND:
				currentSize+=2*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.custom_command.agent);
				currentSize+=determineRASTRINGSize(&command->info.custom_command.message);
				break;
            case RA_BINARY_CUSTOM_COMMAND: /* Bug 73074 */
				currentSize+=2*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.custom_command.agent);
				currentSize+=determineRABinaryArraySize(&command->info.custom_command.message);
				break;
			case RA_AGENT_ACTIVE:
			case RA_AGENT_INACTIVE:
			case RA_AGENT_DETAILS:
				currentSize+=2*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.agent_active.agent);
				currentSize+=determineRASTRINGSize(&command->info.agent_active.processUUID);
				currentSize+=determineRASTRINGSize(&command->info.agent_active.agentUUID);
				currentSize+=determineRASTRINGSize(&command->info.agent_active.agentType);
				break;
			case RA_AGENT_SCOPING_INFORMATION:
				currentSize+=2*sizeof(ra_uint_t);
/* BEGIN:  235649 */
#if defined __linux__
				currentSize+=sizeof(ra_uint_t);
#endif
/* END: 235649 */
				currentSize+=determineRASTRINGSize(&command->info.agent_scoping_information.processUUID);
				currentSize+=determineRASTRINGSize(&command->info.agent_scoping_information.agent);
				currentSize+=determineRASTRINGSize(&command->info.agent_scoping_information.agentUUID);
				currentSize+=determineRASTRINGSize(&command->info.agent_scoping_information.agentType);
				currentSize+=determineRASTRINGSize(&command->info.agent_scoping_information.nodeUUID);
				break;
			case RA_AGENT_CONFIGURATION:
				currentSize+=3*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.agent_configuration.processUUID);
				currentSize+=determineRASTRINGSize(&command->info.agent_configuration.agent);
				currentSize+=determineRASTRINGSize(&command->info.agent_configuration.agentUUID);
				currentSize+=determineRASTRINGSize(&command->info.agent_configuration.agentType);
				currentSize+=determineRASTRINGSize(&command->info.agent_configuration.nodeUUID);
				if(command->info.agent_configuration.configuration.length) {
					for(i=0; i<command->info.agent_configuration.configuration.length; i++) {
						ra_agentConfigEntry_t *entry=((ra_agentConfigEntry_t*)(command->info.agent_configuration.configuration.data[i]));
						currentSize+=determineRASTRINGSize(&entry->type);
						currentSize+=determineRASTRINGSize(&entry->name);
						currentSize+=determineRASTRINGSize(&entry->value);
					}
				}
				break;
			case RA_AGENT_CONTROLER_AVAILABLE:
			case RA_AGENT_CONTROLER_UNAVAILABLE:
				currentSize+=determineRASTRINGSize(&command->info.agentName);
				break;
			case RA_AGENT_REQUEST_MONITOR:
			case RA_CONTROLLER_REQUEST_MONITOR:
			case RA_PEER_UNREACHABLE:
				currentSize+=3*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.agent_request_monitor.agent);
				currentSize+=determineRASTRINGSize(&command->info.agent_request_monitor.node);
				currentSize+=determineRASTRINGSize(&command->info.agent_request_monitor.peerAgent);
				currentSize+=determineRABinaryArraySize(&command->info.agent_request_monitor.peerNode); /* Bug 80893 */
				break;
			/* Bug 77768 begins */
			case RA_AGENT_REQUEST_MONITOR_PORT:
			case RA_CONTROLLER_REQUEST_MONITOR_PORT:
				currentSize+=3*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.agent_request_monitor.agent);
				currentSize+=determineRASTRINGSize(&command->info.agent_request_monitor.node);
				currentSize+=determineRASTRINGSize(&command->info.agent_request_monitor.peerAgent);
				currentSize+=determineRABinaryArraySize(&command->info.agent_request_monitor.peerNode);
				currentSize+=2*sizeof(ra_uint_t); /* The 2 ports */
				break;
			/* Bug 77768 ends */
			case RA_GET_PROPERTY_LIST:
				currentSize+=sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.query_property_list.name);
				currentSize+=determineRASTRINGSize(&command->info.query_property_list.type);
				currentSize+=determineRASTRINGSize(&command->info.query_property_list.agentUUID);
				break;
			case RA_PROPERTY_LIST:
				/* ra_agentConfigEntry_t */
				currentSize+=sizeof(ra_uint_t); /* context */

				/* array length */
				currentSize += sizeof(ra_uint_t);
				/* Names, Types, Values */
				if(command->info.property_list.entries.length) {
					for(i = 0; i < command->info.property_list.entries.length; i++) {
						currentSize += determineRASTRINGSize(&(((ra_agentConfigEntry_t**)command->info.property_list.entries.data)[i]->name));
						currentSize += determineRASTRINGSize(&(((ra_agentConfigEntry_t**)command->info.property_list.entries.data)[i]->type));
						currentSize += determineRASTRINGSize(&(((ra_agentConfigEntry_t**)command->info.property_list.entries.data)[i]->value));
					}
				}
				break;
			/** Added by Giridhar.S on 13/2/04 **/
			case RA_MANAGE_FILE:
				currentSize+=2*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.manage_file.filename);
				break;
			case RA_RESOURCE_LOCATION:
				currentSize+=2*sizeof(ra_uint_t);
				currentSize+=determineRASTRINGSize(&command->info.resource_location.jobKey);
				break;
			} /* switch */
			current=current->next;
		} /* while */
		message->length=currentSize;
		return currentSize;
	} /* if*/
	return 0;
}

/** WRITE_MESSAGE_TO_BUFFER  **************************************************
  * Walks the data structure associted with a message and formats this into a
  * buffer that can then be transfered over a TCP connection.
  * @param       buffer - the previously allocated buffer to copy the message data to.
  * @param bufferLength - the length of the buffer.
  * @param      message - the message data structure to extract the data from.
  * @returns         >0 - the length of the buffer used for the message.
  *                  <0 - buffer is not large enough.
  */
unsigned int ra_writeMessageToBuffer(unsigned char *buffer,
									 unsigned int bufferLength,
									 ra_message_t *message) {
	unsigned char *current;
	ra_command_list_node_t *currentNode;
#ifdef MVS
	unsigned char *tmpbuf;
   unsigned int msglen;
#endif

	/* Is the buffer large enough for the header information */
	if(bufferLength < 12 ) {
		ra_setLastError(0, 0);
		return -1;
	}

#ifdef MVS
/* 190770 - allocate temporary buffer for message to include an extra byte at the end
            for use by copyRASTRINGToBuffer - only necessary for non acknowledgement
            messages */
	if(message->type != RA_ACKNOWLEDGEMENT_MESSAGE) {
      tmpbuf = (unsigned char *)ra_malloc(bufferLength+1);
      current = tmpbuf;
   }
   else {
      current = buffer;
   }
#else
	current=buffer;
#endif

	/* Place the header information in the buffer */
	current=copyRAUINTToBuffer(current, RA_MAGIC);
	current=copyRAUINTToBuffer(current, RA_VERSION);
	current=copyRAUINTToBuffer(current, message->type);
	current=copyRAUINTToBuffer(current, message->ticket);

	if(message->type == RA_ACKNOWLEDGEMENT_MESSAGE) {
		return current-buffer;
	}

	current=copyRAUINTToBuffer(current, message->length);

	/* Is there enough room to add the key? */
#ifdef MVS
	if(bufferLength-(current-tmpbuf) < message->key.length+4 ) {
/* 190770 - copy what we already have to the real message buffer and ra_free the temp space */
      memcpy(buffer, tmpbuf, current-tmpbuf);
      ra_free(tmpbuf);
#else
	if(bufferLength-(current-buffer) < message->key.length+4 ) {
#endif
		ra_setLastError(0, 0);
		return -1;
	}
	current=copyRASTRINGToBuffer(current, &message->key);

	/* Place the command count if there is room */
#ifdef MVS
	if(bufferLength-(current-tmpbuf) < 4 ) {
/* 190770 - copy what we already have to the real message buffer and ra_free the temp space */
      memcpy(buffer, tmpbuf, current-tmpbuf);
      ra_free(tmpbuf);
#else
	if(bufferLength-(current-buffer) < 4 ) {
#endif
		ra_setLastError(0, 0);
		return -1;
	}
	current=copyRAUINTToBuffer(current, message->commands.count);



	/* Copy each of the commands in turn */
	currentNode=message->commands.head;
	while(currentNode != NULL) {
		current=copyRAUINTToBuffer(current, currentNode->command->tag);
		switch(currentNode->command->tag) {
			ra_uint_t i;
		case RA_AUTHENTICATE:
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.authenticate.user);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.authenticate.passwd);
			break;
		case RA_AUTHENTICATION_SUCCESSFUL:
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.authenticate_successful.key);
			break;
		case RA_AUTHENTICATION_FAILED:
            current=copyRAUINTToBuffer(current, currentNode->command->info.authenticate_failed.ticket);
            break;
        case RA_SERVER_SECURITY_REQUIREMENTS:
            current=copyRAUINTToBuffer(current, currentNode->command->info.serverSecurityRequirements.flag);
            current=copyRAUINTToBuffer(current, currentNode->command->info.serverSecurityRequirements.securePort);
            break;
        case RA_QUERY_PROCESS_LIST:
			current=copyRAUINTToBuffer(current, currentNode->command->info.query_process_list.context);
			break;
		case RA_LAUNCH_PROCESS:
			current=copyRAUINTToBuffer(current, currentNode->command->info.launch_process.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.launch_process.consoleIP);
			current=copyRAUINTToBuffer(current, currentNode->command->info.launch_process.consolePort);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.launch_process.executable);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.launch_process.arguments);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.launch_process.location);
			current=copyRAUINTToBuffer(current, currentNode->command->info.launch_process.environment.length);
			for(i=0; i<currentNode->command->info.launch_process.environment.length; i++) {
#ifdef _HPUX
				current=copyRASTRINGToBuffer(current, (ra_string_t *)currentNode->command->info.launch_process.environment.data[i]);
#else
				current=copyRASTRINGToBuffer(current, currentNode->command->info.launch_process.environment.data[i]);
#endif
			}
			current=copyRAUINTToBuffer(current, currentNode->command->info.launch_process.agents.length);
			for(i=0; i<currentNode->command->info.launch_process.agents.length; i++) {
#ifdef _HPUX
				current=copyRASTRINGToBuffer(current, (ra_string_t *)currentNode->command->info.launch_process.agents.data[i]);
#else
				current=copyRASTRINGToBuffer(current, currentNode->command->info.launch_process.agents.data[i]);
#endif
			}
			break;
		case RA_PROCESS_LAUNCHED:
			current=copyRAUINTToBuffer(current, currentNode->command->info.process_launched.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.process_launched.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.process_launched.processUUID);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.process_launched.executable);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.process_launched.arguments);
			current=copyRAUINTToBuffer(current, currentNode->command->info.process_launched.environment.length);
			for(i=0; i<currentNode->command->info.process_launched.environment.length; i++) {
				current=copyRASTRINGToBuffer(current, (ra_string_t *)currentNode->command->info.process_launched.environment.data[i]);
			}
			break;
		case RA_PROCESS_LIST:
			current=copyRAUINTToBuffer(current, currentNode->command->info.registered_process_list.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.registered_process_list.processes.length);
			for(i=0; i<currentNode->command->info.registered_process_list.processes.length; i++) {
				current=copyRAUINTToBuffer(current, *((ra_uint_t*)(currentNode->command->info.registered_process_list.processes.data[i])));
			}
			break;
		case RA_QUERY_AGENT_LIST:
		case RA_KILL_PROCESS:
		case RA_PROCESS_EXITED:
			current=copyRAUINTToBuffer(current, currentNode->command->info.query_agent_list.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.query_agent_list.processId);
			break;
		case RA_AGENT_LIST:
			current=copyRAUINTToBuffer(current, currentNode->command->info.registered_agents_list.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.registered_agents_list.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.registered_agents_list.executable);
			current=copyRAUINTToBuffer(current, currentNode->command->info.registered_agents_list.agents.length);
			for(i=0; i<currentNode->command->info.registered_agents_list.agents.length; i++) {
				current=copyRASTRINGToBuffer(current, (ra_string_t *)currentNode->command->info.registered_agents_list.agents.data[i]);
			}
			break;
		case RA_REGISTER_AGENT_NOTIFICATION:
		case RA_QUERY_AGENT_DETAILS:
			current=copyRAUINTToBuffer(current, currentNode->command->info.register_agent_notification.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.register_agent_notification.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.register_agent_notification.agent);
			break;
		case RA_ATTACH_TO_AGENT:
		case RA_DETACH_FROM_AGENT:
		case RA_STOP_MONITORING_AGENT:
		case RA_AGENT_QUERY_STATE: /* Bug 54376 */
		case RA_AGENT_ATTACHED: /* Bug 54376 */
		case RA_AGENT_DETACHED: /* Bug 54376 */
			current=copyRAUINTToBuffer(current, currentNode->command->info.attach.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.attach.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.attach.agent);
			break;
		case RA_ERROR_STRING:
			current=copyRAUINTToBuffer(current, currentNode->command->info.error_string.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.error_string.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.error_string.agent);
			current=copyRAUINTToBuffer(current, currentNode->command->info.error_string.severity);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.error_string.messageId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.error_string.message);
			break;
		case RA_START_MONITORING_AGENT_REMOTE:
			current=copyRAUINTToBuffer(current, currentNode->command->info.start_monitor_remote.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.start_monitor_remote.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.start_monitor_remote.agent);
			current=copyRAUINTToBuffer(current, currentNode->command->info.start_monitor_remote.ip);
			current=copyRAUINTToBuffer(current, currentNode->command->info.start_monitor_remote.port);
			break;
		case RA_START_MONITORING_AGENT_LOCAL:
			current=copyRAUINTToBuffer(current, currentNode->command->info.start_monitor_local.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.start_monitor_local.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.start_monitor_local.agent);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.start_monitor_local.file);
			break;
		case RA_SET_NAME_VALUE_PAIR:
			current=copyRAUINTToBuffer(current, currentNode->command->info.set_nv_pair.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.set_nv_pair.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.set_nv_pair.agent);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.set_nv_pair.type);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.set_nv_pair.name);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.set_nv_pair.value);
			break;
		case RA_CUSTOM_COMMAND:
			current=copyRAUINTToBuffer(current, currentNode->command->info.custom_command.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.custom_command.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.custom_command.agent);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.custom_command.message);
			break;
        case RA_BINARY_CUSTOM_COMMAND:
            current=copyRAUINTToBuffer(current, currentNode->command->info.custom_command.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.custom_command.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.custom_command.agent);
			current=copyRABinaryArrayToBuffer(current, &currentNode->command->info.custom_command.message);
			break;
		case RA_AGENT_ACTIVE:
		case RA_AGENT_INACTIVE:
		case RA_AGENT_DETAILS:
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_active.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_active.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_active.processUUID);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_active.agent);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_active.agentUUID);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_active.agentType);
			break;
		case RA_AGENT_SCOPING_INFORMATION:
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_scoping_information.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_scoping_information.processId);
/* BEGIN:  235649 */
#if defined __linux__
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_scoping_information.messageProcessId);
#endif
/* END: 235649 */
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_scoping_information.processUUID);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_scoping_information.agent);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_scoping_information.agentUUID);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_scoping_information.agentType);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_scoping_information.nodeUUID);
			break;
		case RA_AGENT_CONFIGURATION:
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_configuration.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_configuration.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_configuration.processUUID);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_configuration.agent);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_configuration.agentUUID);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_configuration.agentType);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_configuration.nodeUUID);
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_configuration.configuration.length);
			for(i=0; i<currentNode->command->info.agent_configuration.configuration.length; i++) {
				ra_agentConfigEntry_t *entry=((ra_agentConfigEntry_t**)currentNode->command->info.agent_configuration.configuration.data)[i];
				current=copyRASTRINGToBuffer(current, &entry->type);
				current=copyRASTRINGToBuffer(current, &entry->name);
				current=copyRASTRINGToBuffer(current, &entry->value);
			}
			break;
		case RA_AGENT_CONTROLER_AVAILABLE:
		case RA_AGENT_CONTROLER_UNAVAILABLE:
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agentName);
			break;
		case RA_AGENT_REQUEST_MONITOR:
		case RA_CONTROLLER_REQUEST_MONITOR:
		case RA_PEER_UNREACHABLE:
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_request_monitor.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_request_monitor.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_request_monitor.agent);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_request_monitor.node);
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_request_monitor.peerProcessId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_request_monitor.peerAgent);
			current=copyRABinaryArrayToBuffer(current, &currentNode->command->info.agent_request_monitor.peerNode); /* Bug 80893 */
			break;
		/* Bug 77768 begins */
		case RA_AGENT_REQUEST_MONITOR_PORT:
		case RA_CONTROLLER_REQUEST_MONITOR_PORT:
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_request_monitor_port.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_request_monitor_port.processId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_request_monitor_port.agent);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_request_monitor_port.node);
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_request_monitor_port.peerProcessId);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.agent_request_monitor_port.peerAgent);
			current=copyRABinaryArrayToBuffer(current, &currentNode->command->info.agent_request_monitor_port.peerNode);
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_request_monitor_port.port);
			current=copyRAUINTToBuffer(current, currentNode->command->info.agent_request_monitor_port.peerPort);
			break;
		/* Bug 77768 ends */
		case RA_GET_PROPERTY_LIST:
			current=copyRAUINTToBuffer(current, currentNode->command->info.query_property_list.context);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.query_property_list.name);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.query_property_list.type);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.query_property_list.agentUUID);
			break;
		case RA_PROPERTY_LIST:
			/* contect */
			current=copyRAUINTToBuffer(current, currentNode->command->info.property_list.context);
			/* Array length */
			current=copyRAUINTToBuffer(current, currentNode->command->info.property_list.entries.length);
			/* Names, Types, Values */
			for(i = 0; i < currentNode->command->info.property_list.entries.length; i++) {
				current=copyRASTRINGToBuffer(current, (ra_string_t*)(&((ra_agentConfigEntry_t**)currentNode->command->info.property_list.entries.data)[i]->name));
				current=copyRASTRINGToBuffer(current, (ra_string_t*)(&((ra_agentConfigEntry_t**)currentNode->command->info.property_list.entries.data)[i]->type));
				current=copyRASTRINGToBuffer(current, (ra_string_t*)(&((ra_agentConfigEntry_t**)currentNode->command->info.property_list.entries.data)[i]->value));
			}
			break;
		/** Added by Giridhar.S on 13/2/04 **/
		case RA_MANAGE_FILE:
			current=copyRAUINTToBuffer(current, currentNode->command->info.manage_file.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.manage_file.operation);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.manage_file.filename);
			break;
		case RA_RESOURCE_LOCATION:
			current=copyRAUINTToBuffer(current, currentNode->command->info.resource_location.context);
			current=copyRAUINTToBuffer(current, currentNode->command->info.resource_location.port);
			current=copyRASTRINGToBuffer(current, &currentNode->command->info.resource_location.jobKey);
			break;
		}

		currentNode=currentNode->next;
	}
#ifdef MVS
/* 190770 - calculate the message length, copy the message to the real buffer
            and ra_free the temp space */
   msglen = current-tmpbuf;
   memcpy(buffer, tmpbuf, msglen);
   ra_free(tmpbuf);
	return msglen;
#else
	return current-buffer;
#endif
}

/** READ_MESSAGE_FROM_BUFFER  *************************************************
  * Read a buffer and create a message_t data structure with all the information
  * contained in the buffer.  Use ra_destroyMessage() to ra_free the associated memory
  * for the message_t structure when finished with it.
  * @param        buffer - the buffer with the data for the message.
  * @param messageLength - the length of the buffer containing the message data.
  * @returns       !NULL - the address of the message created.
  *                 NULL - invalid message data.
  */
ra_message_t* ra_readMessageFromBuffer(unsigned char *buffer,
									   unsigned long messageLength) {

	ra_message_t *message;
	ra_uint_t type, ticket, i, count;
	unsigned char *current;

	/* Extract the type and ticket from the raw buffer and then create the message object */
	current=readRAUINTFromBuffer(&buffer[8], &type);
	current=readRAUINTFromBuffer(current, &ticket);

	message=ra_createMessage(type, ticket);

	/* Was this a valid message type */
	if(!message) {
		return NULL;
	}

	/* If this is an acknowledgment message this is the end of the message */
	if(message->type == RA_ACKNOWLEDGEMENT_MESSAGE) {
		return message;
	}

	current=readRAUINTFromBuffer(current, &message->length);

	/* Extract the key */
	current=readRASTRINGFromBuffer(current, &message->key);


	/* Get the command count */
	current=readRAUINTFromBuffer(current, &count);

	/* Collect each command in turn */
	for(i=0; i<count; i++) {
		/* Allocate the new command */
		ra_command_t *command=(ra_command_t*)ra_malloc(sizeof(ra_command_t));
		current=readRAUINTFromBuffer(current, &command->tag);
		switch(command->tag) {
			ra_uint_t i;
		case RA_AUTHENTICATE:
			current=readRASTRINGFromBuffer(current, &command->info.authenticate.user);
			current=readRASTRINGFromBuffer(current, &command->info.authenticate.passwd);
			break;
		case RA_AUTHENTICATION_SUCCESSFUL:
			current=readRASTRINGFromBuffer(current, &command->info.authenticate_successful.key);
			break;
		case RA_AUTHENTICATION_FAILED:
			current=readRAUINTFromBuffer(current, &command->info.authenticate_failed.ticket);
			break;
        case RA_SERVER_SECURITY_REQUIREMENTS:
            current=readRAUINTFromBuffer(current, &command->info.serverSecurityRequirements.flag);
            current=readRAUINTFromBuffer(current, &command->info.serverSecurityRequirements.securePort);
            break;
		case RA_LAUNCH_PROCESS:
			current=readRAUINTFromBuffer(current, &command->info.launch_process.context);
			current=readRAUINTFromBuffer(current, &command->info.launch_process.consoleIP);
			current=readRAUINTFromBuffer(current, &command->info.launch_process.consolePort);
			current=readRASTRINGFromBuffer(current, &command->info.launch_process.executable);
			current=readRASTRINGFromBuffer(current, &command->info.launch_process.arguments);
			current=readRASTRINGFromBuffer(current, &command->info.launch_process.location);
			current=readRAUINTFromBuffer(current, &command->info.launch_process.environment.length);
			if(command->info.launch_process.environment.length) {
				command->info.launch_process.environment.data=(void**)ra_malloc(sizeof(ra_string_t*)*command->info.launch_process.environment.length);
				for(i=0; i<command->info.launch_process.environment.length; i++) {
					((ra_string_t**)command->info.launch_process.environment.data)[i]=(ra_string_t*)ra_malloc(sizeof(ra_string_t));
					current=readRASTRINGFromBuffer(current, ((ra_string_t*)(((ra_string_t**)command->info.launch_process.environment.data)[i])));
				}
			}
			current=readRAUINTFromBuffer(current, &command->info.launch_process.agents.length);
			if(command->info.launch_process.agents.length) {
				command->info.launch_process.agents.data=(void**)ra_malloc(sizeof(ra_string_t*)*command->info.launch_process.agents.length);
				for(i=0; i<command->info.launch_process.agents.length; i++) {
					((ra_string_t**)command->info.launch_process.agents.data)[i]=(ra_string_t*)ra_malloc(sizeof(ra_string_t));
					current=readRASTRINGFromBuffer(current, (ra_string_t*)(((ra_string_t**)command->info.launch_process.agents.data)[i]));
				}
			}
			break;
		case RA_PROCESS_LAUNCHED:
			current=readRAUINTFromBuffer(current, &command->info.process_launched.context);
			current=readRAUINTFromBuffer(current, &command->info.process_launched.processId);
			current=readRASTRINGFromBuffer(current, &command->info.process_launched.processUUID);
			current=readRASTRINGFromBuffer(current, &command->info.process_launched.executable);
			current=readRASTRINGFromBuffer(current, &command->info.process_launched.arguments);
			current=readRAUINTFromBuffer(current, &command->info.process_launched.environment.length);
			if(command->info.process_launched.environment.length) {
				command->info.process_launched.environment.data=(void**)ra_malloc(sizeof(ra_string_t*)*command->info.process_launched.environment.length);
				for(i=0; i<command->info.process_launched.environment.length; i++) {
					((ra_string_t**)command->info.process_launched.environment.data)[i]=(ra_string_t*)ra_malloc(sizeof(ra_string_t));
					current=readRASTRINGFromBuffer(current, (ra_string_t*)(((ra_string_t**)command->info.process_launched.environment.data)[i]));
				}
			}
			break;
		case RA_QUERY_PROCESS_LIST:
			current=readRAUINTFromBuffer(current, &command->info.query_process_list.context);
			break;
		case RA_PROCESS_LIST:
			current=readRAUINTFromBuffer(current, &command->info.registered_process_list.context);
			current=readRAUINTFromBuffer(current, &command->info.registered_process_list.processes.length);
			if(command->info.registered_process_list.processes.length) {
				command->info.registered_process_list.processes.data=(void**)ra_malloc(sizeof(ra_uint_t*)*command->info.registered_process_list.processes.length);
				for(i=0; i<command->info.registered_process_list.processes.length; i++) {
					((ra_uint_t**)command->info.registered_process_list.processes.data)[i]=(ra_uint_t*)ra_malloc(sizeof(ra_uint_t));
					current=readRAUINTFromBuffer(current, (ra_uint_t*)(((ra_uint_t**)command->info.registered_process_list.processes.data)[i]));
				}
			}
			break;
		case RA_QUERY_AGENT_LIST:
		case RA_KILL_PROCESS:
		case RA_PROCESS_EXITED:
			current=readRAUINTFromBuffer(current, &command->info.query_agent_list.context);
			current=readRAUINTFromBuffer(current, &command->info.query_agent_list.processId);
			break;
		case RA_AGENT_LIST:
			current=readRAUINTFromBuffer(current, &command->info.registered_agents_list.context);
			current=readRAUINTFromBuffer(current, &command->info.registered_agents_list.agents.length);
			current=readRASTRINGFromBuffer(current, &command->info.registered_agents_list.executable);
			command->info.registered_agents_list.agents.data=(void**)ra_malloc(sizeof(ra_string_t*)*command->info.registered_agents_list.agents.length);
			if(command->info.registered_agents_list.agents.length) {
				for(i=0; i<command->info.registered_agents_list.agents.length; i++) {
					((ra_string_t**)command->info.registered_agents_list.agents.data)[i]=(ra_string_t*)ra_malloc(sizeof(ra_string_t));
					current=readRASTRINGFromBuffer(current, (ra_string_t*)(((ra_string_t**)command->info.registered_agents_list.agents.data)[i]));
				}
			}
			break;
		case RA_REGISTER_AGENT_NOTIFICATION:
		case RA_QUERY_AGENT_DETAILS:
			current=readRAUINTFromBuffer(current, &command->info.register_agent_notification.context);
			current=readRAUINTFromBuffer(current, &command->info.register_agent_notification.processId);
			current=readRASTRINGFromBuffer(current, &command->info.register_agent_notification.agent);
			break;
		case RA_ATTACH_TO_AGENT:
		case RA_DETACH_FROM_AGENT:
		case RA_STOP_MONITORING_AGENT:
		case RA_AGENT_QUERY_STATE: /* Bug 54376 */
		case RA_AGENT_ATTACHED: /* Bug 54376 */
		case RA_AGENT_DETACHED: /* Bug 54376 */
			current=readRAUINTFromBuffer(current, &command->info.attach.context);
			current=readRAUINTFromBuffer(current, &command->info.attach.processId);
			current=readRASTRINGFromBuffer(current, &command->info.attach.agent);
			break;
		case RA_ERROR_STRING:
			current=readRAUINTFromBuffer(current, &command->info.error_string.context);
			current=readRAUINTFromBuffer(current, &command->info.error_string.processId);
			current=readRASTRINGFromBuffer(current, &command->info.error_string.agent);
			current=readRAUINTFromBuffer(current, &command->info.error_string.severity);
			current=readRASTRINGFromBuffer(current, &command->info.error_string.messageId);
			current=readRASTRINGFromBuffer(current, &command->info.error_string.message);
			break;
		case RA_START_MONITORING_AGENT_REMOTE:
			current=readRAUINTFromBuffer(current, &command->info.start_monitor_remote.context);
			current=readRAUINTFromBuffer(current, &command->info.start_monitor_remote.processId);
			current=readRASTRINGFromBuffer(current, &command->info.start_monitor_remote.agent);
			current=readRAUINTFromBuffer(current, &command->info.start_monitor_remote.ip);
			current=readRAUINTFromBuffer(current, &command->info.start_monitor_remote.port);
			break;
		case RA_START_MONITORING_AGENT_LOCAL:
			current=readRAUINTFromBuffer(current, &command->info.start_monitor_local.context);
			current=readRAUINTFromBuffer(current, &command->info.start_monitor_local.processId);
			current=readRASTRINGFromBuffer(current, &command->info.start_monitor_local.agent);
			current=readRASTRINGFromBuffer(current, &command->info.start_monitor_local.file);
			break;
		case RA_SET_NAME_VALUE_PAIR:
			current=readRAUINTFromBuffer(current, &command->info.set_nv_pair.context);
			current=readRAUINTFromBuffer(current, &command->info.set_nv_pair.processId);
			current=readRASTRINGFromBuffer(current, &command->info.set_nv_pair.agent);
			current=readRASTRINGFromBuffer(current, &command->info.set_nv_pair.type);
			current=readRASTRINGFromBuffer(current, &command->info.set_nv_pair.name);
			current=readRASTRINGFromBuffer(current, &command->info.set_nv_pair.value);
			break;
		case RA_CUSTOM_COMMAND:
			current=readRAUINTFromBuffer(current, &command->info.custom_command.context);
			current=readRAUINTFromBuffer(current, &command->info.custom_command.processId);
			current=readRASTRINGFromBuffer(current, &command->info.custom_command.agent);
			current=readRASTRINGFromBuffer(current, &command->info.custom_command.message);
			break;
        case RA_BINARY_CUSTOM_COMMAND:
            current=readRAUINTFromBuffer(current, &command->info.custom_command.context);
			current=readRAUINTFromBuffer(current, &command->info.custom_command.processId);
			current=readRASTRINGFromBuffer(current, &command->info.custom_command.agent);
			current=readRABinaryArrayFromBuffer(current, &command->info.custom_command.message);
			break;
		case RA_AGENT_ACTIVE:
		case RA_AGENT_INACTIVE:
		case RA_AGENT_DETAILS:
			current=readRAUINTFromBuffer(current, &command->info.agent_active.context);
			current=readRAUINTFromBuffer(current, &command->info.agent_active.processId);
			current=readRASTRINGFromBuffer(current, &command->info.agent_active.processUUID);
			current=readRASTRINGFromBuffer(current, &command->info.agent_active.agent);
			current=readRASTRINGFromBuffer(current, &command->info.agent_active.agentUUID);
			current=readRASTRINGFromBuffer(current, &command->info.agent_active.agentType);
			break;
		case RA_AGENT_SCOPING_INFORMATION:
			current=readRAUINTFromBuffer(current, &command->info.agent_scoping_information.context);
			current=readRAUINTFromBuffer(current, &command->info.agent_scoping_information.processId);
/* BEGIN:  235649 */
#if defined __linux__
			current=readRAUINTFromBuffer(current, &command->info.agent_scoping_information.messageProcessId);
#endif
/* END: 235649 */
			current=readRASTRINGFromBuffer(current, &command->info.agent_scoping_information.processUUID);
			current=readRASTRINGFromBuffer(current, &command->info.agent_scoping_information.agent);
			current=readRASTRINGFromBuffer(current, &command->info.agent_scoping_information.agentUUID);
			current=readRASTRINGFromBuffer(current, &command->info.agent_scoping_information.agentType);
			current=readRASTRINGFromBuffer(current, &command->info.agent_scoping_information.nodeUUID);
			break;
		case RA_AGENT_CONFIGURATION:
			current=readRAUINTFromBuffer(current, &command->info.agent_configuration.context);
			current=readRAUINTFromBuffer(current, &command->info.agent_configuration.processId);
			current=readRASTRINGFromBuffer(current, &command->info.agent_configuration.processUUID);
			current=readRASTRINGFromBuffer(current, &command->info.agent_configuration.agent);
			current=readRASTRINGFromBuffer(current, &command->info.agent_configuration.agentUUID);
			current=readRASTRINGFromBuffer(current, &command->info.agent_configuration.agentType);
			current=readRASTRINGFromBuffer(current, &command->info.agent_configuration.nodeUUID);
			current=readRAUINTFromBuffer(current, &command->info.agent_configuration.configuration.length);
			command->info.agent_configuration.configuration.data=(void**)ra_malloc(sizeof(ra_agentConfigEntry_t*)*command->info.agent_configuration.configuration.length);
			if(command->info.agent_configuration.configuration.length) {
				for(i=0; i<command->info.agent_configuration.configuration.length; i++) {
					((ra_agentConfigEntry_t**)command->info.agent_configuration.configuration.data)[i]=(ra_agentConfigEntry_t*)ra_malloc(sizeof(ra_agentConfigEntry_t));
					current=readRASTRINGFromBuffer(current, &((ra_agentConfigEntry_t**)command->info.agent_configuration.configuration.data)[i]->type);
					current=readRASTRINGFromBuffer(current, &((ra_agentConfigEntry_t**)command->info.agent_configuration.configuration.data)[i]->name);
					current=readRASTRINGFromBuffer(current, &((ra_agentConfigEntry_t**)command->info.agent_configuration.configuration.data)[i]->value);
				}
			}
			break;
		case RA_AGENT_CONTROLER_AVAILABLE:
		case RA_AGENT_CONTROLER_UNAVAILABLE:
			current=readRASTRINGFromBuffer(current, &command->info.agentName);
			break;
		case RA_AGENT_REQUEST_MONITOR:
		case RA_CONTROLLER_REQUEST_MONITOR:
		case RA_PEER_UNREACHABLE:
			current=readRAUINTFromBuffer(current, &command->info.agent_request_monitor.context);
			current=readRAUINTFromBuffer(current, &command->info.agent_request_monitor.processId);
			current=readRASTRINGFromBuffer(current, &command->info.agent_request_monitor.agent);
			current=readRASTRINGFromBuffer(current, &command->info.agent_request_monitor.node);
			current=readRAUINTFromBuffer(current, &command->info.agent_request_monitor.peerProcessId);
			current=readRASTRINGFromBuffer(current, &command->info.agent_request_monitor.peerAgent);
			current=readRABinaryArrayFromBuffer(current, &command->info.agent_request_monitor.peerNode); /* Bug 80893 */
			break;
		/* Bug 77768 begins */
		case RA_AGENT_REQUEST_MONITOR_PORT:
		case RA_CONTROLLER_REQUEST_MONITOR_PORT:
			current=readRAUINTFromBuffer(current, &command->info.agent_request_monitor_port.context);
			current=readRAUINTFromBuffer(current, &command->info.agent_request_monitor_port.processId);
			current=readRASTRINGFromBuffer(current, &command->info.agent_request_monitor_port.agent);
			current=readRASTRINGFromBuffer(current, &command->info.agent_request_monitor_port.node);
			current=readRAUINTFromBuffer(current, &command->info.agent_request_monitor_port.peerProcessId);
			current=readRASTRINGFromBuffer(current, &command->info.agent_request_monitor_port.peerAgent);
			current=readRABinaryArrayFromBuffer(current, &command->info.agent_request_monitor_port.peerNode);
			current=readRAUINTFromBuffer(current, &command->info.agent_request_monitor_port.port);
			current=readRAUINTFromBuffer(current, &command->info.agent_request_monitor_port.peerPort);
			break;
		/* Bug 77768 ends */
		case RA_GET_PROPERTY_LIST:
			current=readRAUINTFromBuffer(current, &command->info.query_property_list.context);
			current=readRASTRINGFromBuffer(current, &command->info.query_property_list.name);
			current=readRASTRINGFromBuffer(current, &command->info.query_property_list.type);
			current=readRASTRINGFromBuffer(current, &command->info.query_property_list.agentUUID);
			break;
		case RA_PROPERTY_LIST:
			current=readRAUINTFromBuffer(current, &command->info.property_list.context);
			/* Array length */
			current=readRAUINTFromBuffer(current, &command->info.property_list.entries.length);
			/* Names, Types, Values */
			if(command->info.property_list.entries.length) {
				command->info.property_list.entries.data = (void**)ra_malloc(sizeof(ra_agentConfigEntry_t*) * command->info.property_list.entries.length);
				for(i = 0; i < command->info.property_list.entries.length; i++) {
					((ra_agentConfigEntry_t**)command->info.property_list.entries.data)[i] = (ra_agentConfigEntry_t*)ra_malloc(sizeof(ra_agentConfigEntry_t));
					current = readRASTRINGFromBuffer(current, (ra_string_t*)(&((ra_agentConfigEntry_t**)command->info.property_list.entries.data)[i]->name));
					current = readRASTRINGFromBuffer(current, (ra_string_t*)(&((ra_agentConfigEntry_t**)command->info.property_list.entries.data)[i]->type));
					current = readRASTRINGFromBuffer(current, (ra_string_t*)(&((ra_agentConfigEntry_t**)command->info.property_list.entries.data)[i]->value));
				}
			}
			break;
		/** Added by Giridhar.S on 13/2/04 **/
		case RA_MANAGE_FILE:
			current=readRAUINTFromBuffer(current, &command->info.manage_file.context);
			current=readRAUINTFromBuffer(current, &command->info.manage_file.operation);
			current=readRASTRINGFromBuffer(current, &command->info.manage_file.filename);
			break;
		case RA_RESOURCE_LOCATION:
			current=readRAUINTFromBuffer(current, &command->info.resource_location.context);
			current=readRAUINTFromBuffer(current, &command->info.resource_location.port);
			current=readRASTRINGFromBuffer(current, &command->info.resource_location.jobKey);
			break;
		}
		/* Place the command in the command list */
		ra_addCommandToMessage(message, command);
	}
	return message;
}


/** COPY_RASTRING  **************************************************************
  * Creates a copy of the source ra_string_t to the destination ar_string_t.  This
  * does not ra_free any memory currently associated with the destination ra_string_t
  * data portion.
  * @param	destination - the ra_string_t to copy the source data to.
  * @param       source - the source ra_string_t structure.
  */
void ra_copyRASTRING(ra_string_t* destination,
					 const ra_string_t* source) {

	destination->length=source->length;
	destination->data=(char *)ra_malloc(sizeof(char)*source->length+1);
	if(source->data) {
		memcpy(destination->data, source->data, source->length);
	}
	destination->data[source->length]='\0';
}


/** CREATE_RASTRING  ************************************************************
  * Creates an ra_string_t from a null terminated array of characters.  This does
  * a complete copy of the stringBuffer.
  * @param    newString - the address of a ra_string_t structure to load.
  * @param stringBuffer - null terminated buffer of characters to copy into the
  *                       ra_string_t structure.
  */
void ra_createRASTRING(ra_string_t *newString,
					   const char *stringBuffer) {
	if(stringBuffer) {
		newString->length=strlen(stringBuffer);
		newString->data=(char*)ra_malloc(newString->length+1);
		strcpy(newString->data, stringBuffer);
	}
	else {
		newString->length=0;
		newString->data=NULL;
	}
}

/** CREATE_RASTRING2  ***********************************************************
  * Creates an ra_string_t structure from a character buffer.  The data portion
  * of the string is a duplicate of that which is contained in the stringBuffer.
  * @param stringBuffer - address of a null terminated buffer of octets that
  *                       constitutes the data that wii be copied into the new
  *                       ra_string_t structure.
  */
ra_string_t* ra_createRASTRING2(const char *stringBuffer) {
	ra_string_t *newString=(ra_string_t*)ra_malloc(sizeof(ra_string_t));
	ra_createRASTRING(newString, stringBuffer);
	return newString;
}

/** CREATE_RASTRING3  ************************************************************
  * Creates an ra_string_t from an array of characters.  This does
  * a complete copy of the stringBuffer for length characters.
  * @param    newString - the address of a ra_string_t structure to load.
  * @param stringBuffer - null terminated buffer of characters to copy into the
  *                       ra_string_t structure.
  * @param       length - the number of octets to copy into the string.
  */
extern void ra_createRASTRING3(ra_string_t *newString,
							  const char *stringBuffer,
							  unsigned long length) {

	if(stringBuffer && length) {
		newString->length=length;
		newString->data=(char*)ra_malloc(length+1);
		memcpy(newString->data, stringBuffer, length);
	}
	else {
		newString->length=0;
		newString->data=NULL;
	}


}


/** CREATE_RASTRING4  ***********************************************************
  * Creates an ra_string_t structure from a character buffer.  The data portion
  * of the string is a duplicate of that which is contained in the stringBuffer.
  * @param stringBuffer - address of a buffer of octets that
  *                       constitutes the data that wii be copied into the new
  *                       ra_string_t structure.
  * @param       length - the number of octets to copy into the string.
  */
extern ra_string_t* ra_createRASTRING4(const char *stringBuffer,
									   unsigned long length) {
	ra_string_t *newString=(ra_string_t*)ra_malloc(sizeof(ra_string_t));
	ra_createRASTRING3(newString, stringBuffer, length);
	return newString;


}

void ra_destroyRASTRING(ra_string_t *rastring) {
	if (rastring->length > 0) {
		ra_free(rastring->data);
		rastring->data=NULL;
		rastring->length=0;
	}
}

/** SET_LAST_ERROR ***********************************************
  * Whenever a call fails to to any of the "jvmpicomm" functions
  * set last error is called to store a global error code that
  * relates to the failure and return -1 to the caller.  These
  * errors are defined in PIError.h and can be retrieved by the
  * caller for error determination/logging.
  */
void ra_setLastError(ra_uint_t major, ra_uint_t minor) {
	_raLastErrorMajor=major;
	_raLastErrorMinor=minor;

}


/** GET_LAST_ERROR_MAJOR ***********************************************
  * Retrieves the last error posted to setLastError.  This is the
  * Project dependant error that is located in PIError.h.
  * @returns  the contents of the last error flag.
  */
ra_uint_t ra_getLastErrorMajor(void) {
	return _raLastErrorMajor;
}

/** GET_LAST_ERROR_MINOR ***********************************************
  * Retrieves the last error posted to setLastError.  This is the OS
  * specific error.
  * @returns  the contents of the last error flag.
  */
ra_uint_t ra_getLastErrorMinor(void) {
	return _raLastErrorMinor;
}

/** GENERATE_UUID  ************************************************
  * Creates an ra_string_t containing a UUID.
  * @param  uuid - the address of the ra_string_t to load the UUID into.
  */
void ra_generateUUID(ra_string_t *uuid) {
#ifdef _WIN32
	UUID temp;
	char *result;
	UuidCreate(&temp);
	UuidToString(&temp, &result);
	uuid->length=strlen(result);
	uuid->data=strdup(result);
	RpcStringFree(&result);
#else
	/* RKD:  This isn't a real UUID but should be close enough for our purposes */
	static BOOL firstTime=TRUE;
	static unsigned short seed[3];
	struct timeval tv;
	#ifndef MVS
		struct timezone tz;
	#endif
	unsigned long seconds, microseconds;
	char *buffer;

	buffer=(char*)ra_malloc(128);
	if(buffer) {
      BZERO(buffer, 128);
		/* Get a timestamp */
		#ifdef MVS
			gettimeofday(&tv, 0);
		#else
			gettimeofday(&tv, &tz);
		#endif
		seconds=tv.tv_sec;
		microseconds=tv.tv_usec;

		/* Seed our generator on the first pass */
		if(firstTime) {
			seed[0]=seconds;
			seed[1]=microseconds;
			seed[2]=0;
#ifdef __OS400__
			srand(microseconds);
#else
			seed48(seed);
#endif
			firstTime=FALSE;
		}

		/* Generate the randon part of the UUID */
#ifdef __OS400__
		sprintf(buffer, "UUID-%d-%d-%d-%d", seconds, microseconds, rand(), rand());
#elif MVS
/*    188870 - snprintf not available on 390 */
		sprintf(buffer, "UUID-%d-%d-%d-%d", seconds, microseconds, lrand48(), lrand48());
#else
		snprintf(buffer, 128, "UUID-%d-%d-%d-%d", (int)seconds, (int)microseconds, (int)lrand48(), (int)lrand48());
#endif
		buffer[127]='\0';
		uuid->length=strlen(buffer);
		uuid->data=buffer;
		return;

	}
	uuid->length=0;
	uuid->data=NULL;
#endif
}

void* ra_malloc(unsigned int blockSize) {
	return malloc(blockSize);
}

void ra_free(void *block) {
	free(block);
}


/** ATOMIC_CAS  ****************************************************************
  * Atomic compare and swap of a 32 bit element. If the compare 
  * (*addr == *oldval_addr) is successful, assigns newval to *addr. 
  * Otherwise, assigns *addr to *oldval_addr. 
  * @param         addr - the address of the data to change.
  * @param  oldval_addr - the address to store the previous value into.
  * @param       newval - the newvalue to put in the memory at addr.
  * @returns -  TRUE if the CAS was successful.
  *          -  FALSE otherwise.
  */
_inline BOOL ra_atomicCAS(atomic_p addr, int *oldval_addr, int newval) {
#ifdef _NO_ATOMIC_CAS
	/* We don't need to test to ensure the value has not changed as this is
	   in a mutex.  Se comments by _cas_mutex declaration for conditions
	   that must be satisfied for this to be true.
	*/
	pthread_mutex_lock(&_cas_mutex);
	*addr=newval;
	pthread_mutex_unlock(&_cas_mutex);
	return TRUE;
#elif defined _WIN32
#ifndef _WIN64
	__asm {
			mov     edx, addr
			mov     ebx, oldval_addr
			mov     eax, [ebx]			; Load contents of oldval_addr into EBX
			mov     ecx, newval
			lock cmpxchg [edx], ecx		; Compare & Exchange *(EDX) == EAX

			jnz		nomatch			; If the compare failed, jump
			mov		eax, 1			; Set our return value for the passed test
			jmp     getout				; Were done!

		nomatch:	          			; EAX has the contents of addr, move them
			mov     [ebx], eax      	        ;   into oldval_addr
			mov		eax, 0			; Set the return value for the failed test

		getout:
	}
#else
/* This code crashes piAgent!
	int *old;
	old = (int *)InterlockedCompareExchange( (PLONG)addr, (LONG)oldval_addr, (LONG)&newval ) ;
	return ( *old == newval ) ;
*/
	*addr=newval;
	return TRUE;
#endif
#elif __linux__
	#if defined (__i386__)
		int oldval = *oldval_addr;
		return (oldval ==__cmpxchg(addr, oldval, newval, 4));
	#elif defined (__powerpc64__)
		int oldval = *oldval_addr;
		return (oldval == cmpxchg(addr, oldval, newval));
	#elif defined (__s390__)
		int oldval = *oldval_addr;
		if(atomic_compare_and_swap(oldval, newval, addr)) {
			return FALSE;
		}
		else {
			return TRUE;
		}
	#endif
#elif _AIX
	return compare_and_swap(addr, oldval_addr, newval);
#elif MVS
	if(cs(oldval_addr, addr, newval)) {
		return FALSE;
	}
	return TRUE;
#elif _SOLARIS
	/* RKD:  This would probably work on Solaris providing we have the assembler
	         set such that it supports v8 plus.  In order to support lower levels
			 we may need to use pthread locking.
	*/
	asm("cas    [%o0], %o1, %o2");
	asm("mov    1, %o0");            /*! Set rc=1 */
	asm("cmp    %o1, %o2");         /*! Check to see if the cas was successful */
	asm("move   %icc, 0, %o0");     /*! rc=0 (Use cond. move to prevent branch inst.)*/
#elif _HPUX
	/* RKD:  I looked for a instruction or library call to do this with no avail.
	         It looks like pthread_mutextes may be required.  I did, however, come
			 across the following information:

			 If the threads were spawned using pthreads,
			 you must use the pthreads mutexes.

			 Building at +O3 +Oparallel.

			If you are going parallel using cpslib, then you can use cps_mutex_lock/
			cps_mutex_unlock (which, b.t.w. are simply aliases for __cps_begin_critical/
			__cps_end_critical). These are faster than the pthreads mutexes because
			they use spin locks to wait rather than suspending a waiting thread.
			If you are *really sure* you know what you are doing, you could use
			the low-level m_lock/m_unlock, which are slightly faster than cps_mutex_lock/
			cps_mutex_unlock, but do absolutely no error checking at all.
    */
	return FALSE;
#elif __OS400__
	if(_CMPSWP(oldval_addr, addr, newval)) {
		return TRUE;
	}
	return FALSE;
#else
		return FALSE;
#endif
}

/** ATOMIC_INCREMENT_BY_VALUE  *************************************************
  * Atomic increment of a value by a specified amount.
  * @param     value - the address of the value to increment.
  * @param increment - the amount to increment value by.
  * @returns  - the new value.
  */
_inline int ra_atomicIncVal(volatile int *value, int increment) {
   int newval = *value;
   while(!ra_atomicCAS((atomic_p)value, &newval, newval+increment)) {
	   newval=*value;
   }
   return newval+increment;
}

/** ATOMIC_INCREMENT  **********************************************************
  * Atomic increment a value by one(1).
  * @param value - the address of the value to increment
  * @returns - the new value
  */
_inline int ra_atomicInc(volatile int *value) {
   return ra_atomicIncVal(value, 1);
}

/** CRITICAL_SECTION_CREATE  ***************************************************
  * Create a critical section.
  */
void ra_mutexCreate(ra_critsec_t *lock) {
#ifdef _WIN32
	InitializeCriticalSection(lock);
#else
	pthread_mutex_init(lock, 0); /* unlocked by default */
#endif
}

/** CRITICAL_SECTION_ENTER  ***********************************************************
  * Enter a previously created critical section on this thread.
  */
void ra_mutexEnter(ra_critsec_t *lock) {
#ifdef _WIN32
	EnterCriticalSection(lock);
#else
	pthread_mutex_lock(lock);
#endif
}

/** CRITICAL_SECTION_EXIT  ************************************************************
  * Exit a previously entered critical section on this thread.
  */
void ra_mutexExit(ra_critsec_t *lock) {
#ifdef _WIN32
	LeaveCriticalSection(lock);
#else
	pthread_mutex_unlock(lock);
#endif
}

/** CRITICAL_SECTION_DESTROY  *********************************************************
  * Destroy a critical section.
  */
void ra_mutexDestroy(ra_critsec_t *lock) {
#ifdef _WIN32
	DeleteCriticalSection(lock);
#else
	pthread_mutex_destroy(lock);
#endif
}

/** CREATE PIPE  ****************************************************
  * Create an anonymous pipe.
  * @param  readEnd - the address to store the file descriptor of the
  *                   end of the pipe that will be read from.
  * @param writeEnd - the address to store the file descriptor of the
  *                   end of the pipe that will be written to.
  * @returns   TRUE - pipe creation was successful.
  *           FALSE - otherwise - use ra_getLastErrorMajor/Minor for
  *                   details.
  */
BOOL ra_createPipe(RA_HANDLE *readEnd,
				   RA_HANDLE *writeEnd) {
#ifdef _WIN32
	BOOL result;
	SECURITY_ATTRIBUTES sa;
	ZeroMemory(&sa, sizeof(sa));
	sa.bInheritHandle=TRUE;
	sa.nLength=sizeof(sa);
	result=CreatePipe(readEnd, writeEnd, &sa, 2<<10);
	if(!result) {
		*readEnd=RA_HANDLE_NULL;
		*writeEnd=RA_HANDLE_NULL;
		ra_setLastError(RA_PIPE_CREATE_FAILED, GetLastError());
		return FALSE;
	}
#else
	int result;
	int *fd=(int*)ra_malloc(sizeof(int)*2);
	BZERO(fd, 2);
	result=pipe(fd);
/* 170752 begin - changed from &fd[] to fd[] */
	*readEnd=fd[0];
	*writeEnd=fd[1];
/* 170752 end */
	if(result) {
/* 170752 begin - initialize to zero instead of NULL */
		*readEnd=0;
		*writeEnd=0;
/* 170752 end */
		ra_setLastError(RA_PIPE_CREATE_FAILED, errno);
		return FALSE;
	}
#endif
	return TRUE;
}

/** CREATE NAMED PIPE  ****************************************************
  * Create a named pipe to share data across processes.
  * @param  name - the name of the pipe.  THIS IS PLATFORM SPECIFIC.  On
  *                Windows the name must have the following structure
  *                \\.\pipe\pipename, where pipename is the unique name
  *                for the pipe.
  *                On Unix, the name must be a filename andhense must have
  *                a valid path.
  */
RA_HANDLE ra_createNamedPipe(const char *name) {
	RA_HANDLE result = (RA_HANDLE)-1; /* 46651 changed from RA_HANDLE_NULL since 0 is a valid file descriptor */
	char pipeName[256];

#ifdef _WIN32

	SECURITY_ATTRIBUTES sa;
	ZeroMemory(&sa, sizeof(sa));
	sa.bInheritHandle=TRUE;
	sa.nLength=sizeof(sa);

	/* Build the pipe name for the platform */
	strcpy(pipeName, RA_PIPE_NAMESPACE);
	strcat(pipeName, name);

	/* Need to change the name so that it is a valid pipe name on Windows \\.\pipe\pipename */
	result=CreateNamedPipe(pipeName,				/* The name of the pipe */
						   PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED | WRITE_DAC,	/* Open as inbound pipe - 199740 and give permission to change security */
						   PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, /* byte pipe with blocking disabled */
						   1,						/* No more then 1 instance */
						   4096,					/* The output buffer size of the pipe */
						   4096,					/* The input buffer size of the pipe */
						   3000,					/* Default timeout value is three seconds */
						   &sa);					/* Security attributes of the pipe */
	if(result==INVALID_HANDLE_VALUE) {
		result = (RA_HANDLE)-1; /* 46651 changed from RA_HANDLE_NULL since 0 is a valid file descriptor */
		ra_setLastError(RA_PIPE_CREATE_FAILED, GetLastError());
	}
/* 199740 begin */
    else {
		/* Try to disable the security for the named pipe just created so other prcesses can connect to it */
		disableAllSecurityOfKernalObject(result);
    }
/* 199740 end */
#else
	mode_t fcrtmask;   /* 203936 */

	/* Build the pipe name for the platform */
	strcpy(pipeName, RA_PIPE_NAMESPACE);
	strcat(pipeName, name);

	/* Set the file creation mask so all permissions can be set */
	fcrtmask = umask(0000);      /* 203936 */

	/* Ensure the RA_PIPE_NAMESPACE directory exists and that everyone can access it */
	/* result=mkdir(RA_PIPE_NAMESPACE, S_IRWXO); */
	result=mkdir(RA_PIPE_NAMESPACE, 0777); /* S_IRWXO doesn't work on Red Hat Linux 7.2 */

	/* Need to convert the name to a path */
	if(mkfifo(pipeName, 0666)) {
		ra_setLastError(RA_PIPE_CREATE_FAILED, errno);
		result = -1; /* 46651 changed from RA_HANDLE_NULL since 0 is a valid file descriptor */
	}
	else {
		/* Since mkfifo() does not return a valid file descriptor we will fill
		   in a bogus value right now and the ra_connectToNamedPipe() will
		   fill in the real descriptor.
		*/
		result = 0; /* 46651 changed from RA_HANDLE_NULL since 0 is a valid file descriptor */
		/*
		result=open(name, O_RDONLY);
		if(result<=0) {
			ra_setLastError(RA_PIPE_CREATE_FAILED, errno);
			result=RA_HANDLE_NULL;
		}
		*/
	}

	/* reset the file creation mask back to what it was */
	umask(fcrtmask);  /* 203936 */
#endif
	return result;
}

/** DESTROY_NAMED_PIPE  ********************************************************
  * Called on a server pipe to destroy the pipe.
  */
extern BOOL ra_destroyNamedPipe(const char *name){
#ifndef _WIN32
	char pipeName[256];

	if(name == NULL) {
	        return FALSE; /* 54876 */
	}

	/* Build the pipe name for the platform */
	strcpy(pipeName, RA_PIPE_NAMESPACE);
	strcat(pipeName, name);

	/* if unlink fails then return FALSE - 204804 */
	if (unlink(pipeName)) {
		return FALSE;
	}
#endif
	return TRUE;
}

/** CONNECT_NAMED_PIPE  ********************************************************
  * Used by the creater of a named pipe to connect to a previously created named
  * pipe for reading and waits for another application to open the pipe for writing. 
  * Note: This is a blocking call (i.e., the call will not return until someone else
  * has opened the pipe for writing.)
  * @param handle - the handle returned from a successful call to
  *                 ra_createNamedPipe()
  */
BOOL ra_connectToNamedPipe(RA_HANDLE *handle,  const char *name) {
	BOOL result=FALSE;
#ifdef _WIN32
	OVERLAPPED overlap;

	if(handle==INVALID_HANDLE_VALUE) {
		ra_setLastError(RA_NOT_PIPE, 0);
	}
	/* RKD:  As we create the pipe so it is non-blocking we need to wait for the
	         device to be signaled as the connect does not block.  Because the
			 pipe is an object it will be signaled when the request completes.
	*/
	BZERO(&overlap, sizeof(OVERLAPPED));
	overlap.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
	result=ConnectNamedPipe(*handle, &overlap);
	if(!result) {
		long error=GetLastError();

		/* Is the error just because the client beat us to the punch */
		if(error==ERROR_PIPE_CONNECTED) {
			result=TRUE;
			CloseHandle(overlap.hEvent);
			return result;
		}
		else {
			ra_setLastError(RA_PIPE_CONNECT_FAILED, GetLastError());
		}
	}
	WaitForSingleObject(overlap.hEvent, INFINITE); 
	CloseHandle(overlap.hEvent);
	result=TRUE;
#else
	char pipeName[256];

	/* Build the pipe name for the platform */
	strcpy(pipeName, RA_PIPE_NAMESPACE);
	strcat(pipeName, name);

	/* Open the file */
	*handle=open(pipeName, O_RDONLY);
#if defined(MVS)
	pthread_testintr(); /* APAR PK01709 */
#endif
	if(*handle < 0) { /* 46651 changed from RA_HANDLE_NULL since 0 is a valid file descriptor */
		ra_setLastError(RA_PIPE_CONNECT_FAILED, errno);
		*handle = -1; /* 46651 changed from RA_HANDLE_NULL since 0 is a valid file descriptor */
	}
	else {
		result=TRUE;
	}
#endif
	return result;
}


/** DISCONNECT_NAMED_PIPE  *****************************************************
  * Called by the server pipe to disconnect from a pipe.
  */
extern BOOL ra_disconnectFromNamedPipe(RA_HANDLE handle) {
#ifdef _WIN32
	FlushFileBuffers(handle);
	return DisconnectNamedPipe(handle);
#else
	close(handle); /* 46651 ramaster pipe is opened repeatly without closing by the RACInternalServer loop */
	return TRUE;
#endif
#if 0
	close(handle);
#endif
}

/** OPEN_NAMED_PIPE  ***********************************************************
  * Opens a pipe for writing. Note: This is a NON-blocking call. If another process
  * has yet to open a pipe for reading, this call will return immediately with 
  * a negative value. The intention is for the caller of this method to loop until 
  * a non-negative value is returned, which indicates a successful connection to 
  * the pipe. 
  */
RA_HANDLE  ra_openNamedPipe(const char *name) {
	RA_HANDLE result;
	char pipeName[256];
#ifndef _WIN32
	int old_flags; 
#endif

	if(name == NULL) {
		return (RA_HANDLE)-1; /* 54876 */ /* 46651 changed from RA_HANDLE_NULL since 0 is a valid file descriptor */
	}

	/* Build the pipe name for the platform */
	strcpy(pipeName, RA_PIPE_NAMESPACE);
	strcat(pipeName, name);

#ifdef _WIN32
	/* Attempt to wait until we are accepted as a client to the pipe server.  A couple of things can happen
	   here.  First, if there is no client it will return immediately.  If there is a client it will either
	   successfuly wait or we will timeout waiting.  If we timeout then try again.
	*/

	if(!WaitNamedPipe(pipeName, 3000)) {
		DWORD error=GetLastError();

		/* RKD:  We could wait forever above.  I'm not 100% confident what all the return codes
		         can be so we will start with this code.
		*/

		if(error==ERROR_SEM_TIMEOUT) {
			/* goto tryAgain; */ /* do not loop -- this call is "non-blocking" */ 
		}
		result = (RA_HANDLE)-1; /* 46651 changed from RA_HANDLE_NULL since 0 is a valid file descriptor */
		ra_setLastError(RA_PIPE_OPEN_FAILED, error);
		return result;
	}
	result=CreateFile(pipeName,						/* The name of the named pipe */
					  GENERIC_WRITE,				/* write access */
					  0,							/* no sharing */
					  NULL,							/* default security attributes */
					  OPEN_EXISTING,				/* opens existing pipe */
					  FILE_FLAG_OVERLAPPED,			/* asyncronous I/O  */
					  NULL);						/* no template file */

	if(result==INVALID_HANDLE_VALUE) {
		long error=GetLastError();
		ra_setLastError(RA_PIPE_OPEN_FAILED, error);
		result = (RA_HANDLE)-1; /* 46651 changed from RA_HANDLE_NULL since 0 is a valid file descriptor */
	}
#else

	/* Open the file */
	result=open(pipeName, O_WRONLY | O_NONBLOCK);
#if defined(MVS)
	pthread_testintr(); /* APAR PK01709 */
#endif
	if(result < 0 )  {   /* 203936 - if open fails result can be negative */ /* 46651 changed from RA_HANDLE_NULL since 0 is a valid file descriptor */
		ra_setLastError(RA_PIPE_OPEN_FAILED, errno);
		result = -1; /* 46651 changed from RA_HANDLE_NULL since 0 is a valid file descriptor */
	}
	else {
		/* unset the O_NONBLOCK flag */ 
		old_flags = fcntl(result, F_GETFL); 
		old_flags &= ~O_NONBLOCK; 
		fcntl(result, F_SETFL,old_flags); 
	}
#endif /* _WIN32 */
	return result;
}

/** CLOSE_NAMED_PIPE  **********************************************************
  * Closes an open named pipe.
  * @param handle - the handle to the open named pipe.
  */
BOOL ra_closeNamedPipe(RA_HANDLE handle) {
#ifdef _WIN32
	FlushFileBuffers(handle);
	return CloseHandle(handle);
#else
	/* check if handle is valid ie ra_connectToNamedPipe or ra_openNamedPipe has been called - 203936 */
	if (handle >= 0) { /* 46651 changed from RA_HANDLE_NULL since 0 is a valid file descriptor */
		close(handle);
	}
	return TRUE;
#endif
}

/** READ_FROM_NAMED_PIPE  ******************************************************
  *
  */
int ra_readFromNamedPipe(RA_HANDLE handle,
						 char *buffer,
						 int offset,
						 int length,
						 int *bytesRead) {
#ifdef _WIN32
	int result;
	BOOL res;
	OVERLAPPED overlap;
	BZERO(&overlap, sizeof(OVERLAPPED));
	overlap.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
	/* RKD:  Reading and writing on the same pipe cannot be done synchronously in our model. */
	res=ReadFile(handle, buffer+offset, length-offset, bytesRead, &overlap);
	if(!res) {
		long error=GetLastError();
		if(error!= ERROR_IO_PENDING) {
			CloseHandle(overlap.hEvent);
			return -1;
		}
	}
	WaitForSingleObject(overlap.hEvent, INFINITE);
	GetOverlappedResult(handle, &overlap, bytesRead, FALSE);
	CloseHandle(overlap.hEvent);
	result=*bytesRead;
	return result;
#else
	ssize_t byte;
	int result;

	byte=read(handle, buffer+offset, length-offset);

	if(byte==0) {
		result=0;
		*bytesRead=0;
	}
	else if(byte<0) {
		ra_setLastError(RA_PIPE_READ_FAILED, errno);
		result=-1;
		*bytesRead=0;
	}
	else {
		result=1;
		*bytesRead=byte;
	}
	return result;
#endif
}


/**  WRITE_TO_NAMED_PIPE  ****************************************************
  *
  */
int ra_writeToNamedPipe(RA_HANDLE handle,
					  char *buffer,
					  int offset,
					  int length,
					  int *bytesWritten) {
#ifdef _WIN32
	int result;
	OVERLAPPED overlap;
	BZERO(&overlap, sizeof(OVERLAPPED));
	overlap.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
	/* RKD:  Reading and writing on the same pipe cannot be done synchronously in our model. */
	result=WriteFile(handle, buffer+offset, length-offset, bytesWritten, &overlap);
	if(!result) {
		long error=GetLastError();
		if(error!= ERROR_IO_PENDING) {
			CloseHandle(overlap.hEvent);
			return -1;
		}
	}
	WaitForSingleObject(overlap.hEvent, INFINITE);
	GetOverlappedResult(handle, &overlap, bytesWritten, FALSE);
	CloseHandle(overlap.hEvent);
	return *bytesWritten;
#else
	int result;
	/* Bug 146962 begins */
	int start;
	int bytesWrittenSoFar = 0;
	int retry = 10;

	do {
		int written;
		start = offset + bytesWrittenSoFar;
		written = write(handle, (unsigned char*)buffer + start, length - start);
		if(written > 0) {
			bytesWrittenSoFar += written;
		}
		if(bytesWrittenSoFar < length - offset) {
			SLEEP(500);
		}
	} while((bytesWrittenSoFar < length - offset) && (retry-- > 0));

	if(bytesWrittenSoFar == 0) {
		result = 0;
		*bytesWritten = 0;
	}
	else if(bytesWrittenSoFar < 0) {
		result = -1;
		*bytesWritten = 0;
	}
	else {
		result = 1;
		*bytesWritten = bytesWrittenSoFar;
	}
	/* Bug 146962 ends */

	return result;
#endif
}

/*
 *  OS/400 code page conversion functions
 */
#ifdef __OS400__ /* 236501 */

/*
 * @param - buffer - the buffer where the converted string can be written. If no
 *       buffer is passed in, then one is created. 
 */ 
 
char* as400_convert_tobuffer(char* from_str, char* from_code, char* to_code, 
							 char *buffer) {
	iconv_t cd;
	char* to_str;
	char* to_str_base;
	size_t from_len;
	size_t to_len;

	from_len = strlen(from_str);
	if(from_len > 16773104) /* max for AS/400 */
		return NULL;

	to_len = from_len + 1;
	if (buffer) {
		to_str = buffer; 
	}
	else {
		to_str = (char*)ra_malloc(to_len);
	}
	to_str_base = to_str;
	BZERO(to_str, to_len);

	cd = iconv_open(to_code, from_code);
	iconv(cd, &from_str, &from_len, &to_str, &to_len);
	iconv_close(cd);

	return to_str_base;
}

char* as400_convert(char* from_str, char* from_code, char* to_code) {
	return as400_convert_tobuffer(from_str,from_code,to_code,0); 
}

char* as400_atoe(char* from_str) {
	return as400_convert(from_str, "IBMCCSID0081900000000000000000000", "IBMCCSID0000000000000000000000000"); /* ASCII to EBCDIC */
}

/* writes atoe conversion into a specified buffer */ 
char* as400_atoe_tobuffer(char* from_str, char *buffer) {
	return as400_convert_tobuffer(from_str, "IBMCCSID0081900000000000000000000", "IBMCCSID0000000000000000000000000",buffer); /* ASCII to EBCDIC */
}

/* writes etoa conversion into a specified buffer */ 
char *as400_etoa_tobuffer(char* from_str, char *buffer) {
	return as400_convert_tobuffer(from_str, "IBMCCSID0000000000000000000000000", "IBMCCSID0081900000000000000000000",buffer); /* EBCDIC to ASCII */
}

char* as400_etoa(char* from_str) {
	return as400_convert(from_str, "IBMCCSID0000000000000000000000000", "IBMCCSID0081900000000000000000000"); /* EBCDIC to ASCII */
}

char* as400_atou(char* from_str) {
	return as400_convert(from_str, "IBMCCSID0081900000000000000000000", "IBMCCSID0120800000000000000000000"); /* ASCII to UTF-8 */
}

char* as400_utoa(char* from_str) {
	return as400_convert(from_str, "IBMCCSID0120800000000000000000000", "IBMCCSID0081900000000000000000000"); /* UTF-8 to ASCII */
}

int parseServicePgmName(char *inputSrvpgmName, char *libraryName, char *srvpgmName) 
{
  int inputNameLen = 0;
  int index = 0;
  int slashIndex = 0;

  inputNameLen = strlen(inputSrvpgmName);

  /* Looking for '/' in the name */
  for (index=0; index<inputNameLen; ++index)
  {
    if (inputSrvpgmName[index] == '/')
    {
      slashIndex = index;
      break;
    }/*end if*/
  }/*end for*/

  if (0 == slashIndex)
  {
    /* user only input the service program name, use *LIBL as libraryName */
    strncpy(libraryName, "*LIBL", 5);
    /*null terminate the libraryName*/
    libraryName[5] = '\0';
    strcpy(srvpgmName, inputSrvpgmName);
  }/*end if */
  else
  {
     if (10 < slashIndex)
     {
       /*more than 10 characters in the library name*/
       return -1;
     }/* end if */
     else
     {
       if (inputNameLen-slashIndex - 1 > 10) 
       {
         /* more than 10 characters in the service program name */
         return -1;
       }/*end if*/
       strncpy(libraryName, inputSrvpgmName, slashIndex);
       /*null terminate the libraryName*/
       libraryName[slashIndex] = '\0';
       strcpy(srvpgmName, inputSrvpgmName+slashIndex+1);
     }/* end else */
  }/* end if */

  return 0;
}

/*****************************************************************************/
/*                                                                                                                             */
/*  This function will resolve the service program and active it.                                          */
/*  If no service program is found, or any error occurs during the activation process,             */
/*  a NULL will be returned.                                                                                          */
/*                                                                                                                             */
/*  Bugzilla #57112 - adding LOADLIBRARY support for OS400                                          */
/*  format expected for srvpgmName:                                                                            */
/*         SRVPGMNAME          max 10 characters.                                                             */
/*         LIBNAME/SRVPGMNAME   max 10 characters for each part                                     */
/*  expect there is no leading and trailing white space in the srvpgmName string                 */
/*                                                                                                                             */
/*****************************************************************************/
void *loadServicePgm(char *inputSrvpgmName)
{
  char libraryName[11];
  char srvpgmName[11];
  int returnCode = 0;

  _SYSPTR sysP;
   _OBJ_TYPE_T objectType = WLI_SRVPGM;
   Qus_EC_t err = {
       0,              /* bytes provided   */
       0               /* bytes available  */
   };
   Qle_ABP_Info_t activationInfo;
   int actInfoLen = sizeof(activationInfo);
   int hdl;
   int exportType;
   void *procAddress = NULL;

  
  /*Parse the service program name first. */
  /*It could be LIBNAME/SRVNAME or just SRVNAME*/
  if (NULL == srvpgmName)
  {
    return NULL;
  }
  returnCode = parseServicePgmName(inputSrvpgmName, libraryName, srvpgmName);

  if (-1 == returnCode)
  {
    /* something wrong with the inputSrvpgmName */
    return NULL;
  }

  /*-----------------------------------------------------------------------*/
   /* resolve to the service program                                 */
   /*-----------------------------------------------------------------------*/
   /* capture any type of error and if any occurs, return not found */
  #pragma exception_handler(error,0,0,_C2_MH_ESCAPE,_CTLA_HANDLE_NO_MSG)

   sysP = rslvsp(objectType, srvpgmName, libraryName, _AUTH_EXECUTE);

   if (NULL == sysP)
   {
     return NULL;
   }

   /*----------------------------------------------------------------------*/
   /* activate the service program                                    */
   /*----------------------------------------------------------------------*/
   QleActBndPgm(&sysP, &hdl, &activationInfo, &actInfoLen, &err);

   if (err.Bytes_Provided > 0)
   {
     /* something wrong.  return NULL */
     return NULL;
   }

   return sysP;

   #pragma disable_handler
 error:
    return(NULL);

  
}

/*****************************************************************************/
/*                                                                                                                             */
/*  This function will Then it will find the function pointer of the entry and return it.            */
/*  If no service program is found, or any error occurs during the activation process,             */
/*  a NULL will be returned.                                                                                          */
/*                                                                                                                             */
/*  Bugzilla #57112 - adding LOADLIBRARY support for OS400                                          */
/*                                                                                                                             */
/*****************************************************************************/
void *findServicePgmEntry(void *inputSrvpgmHandle, char* entryName)
{
  
  _SYSPTR sysP;
   _OBJ_TYPE_T objectType = WLI_SRVPGM;
   Qus_EC_t err = {
       0,              /* bytes provided   */
       0               /* bytes available  */
   };
   Qle_ABP_Info_t activationInfo;
   int actInfoLen = sizeof(activationInfo);
   int hdl;
   int exportType;
   void *procAddress = NULL;

   sysP = (_SYSPTR)inputSrvpgmHandle;
   
   /*----------------------------------------------------------------------*/
   /* activate the service program                                    */
   /*----------------------------------------------------------------------*/
   /* capture any type of error and if any occurs, return not found */
  #pragma exception_handler(error1,0,0,_C2_MH_ESCAPE,_CTLA_HANDLE_NO_MSG)
   QleActBndPgm(&sysP, &hdl, &activationInfo, &actInfoLen, &err);

   if (err.Bytes_Provided > 0)
   {
     /* something wrong.  return NULL */
     return NULL;
   }
   /*----------------------------------------------------------------------*/
   /* get procedure pointer and return it to caller         */
   /*----------------------------------------------------------------------*/
   QleGetExp(0, 0, 0, entryName, &procAddress, &exportType,&err);

   if (err.Bytes_Provided > 0)
   {
     /* something wrong.  return NULL */
     return NULL;
   }
   
   return procAddress;

   #pragma disable_handler
 error1:
    return(NULL);

}
#endif

#ifndef _WIN32
char* itoa(int value, char* string, int radix) {
	sprintf(string, "%d", value);
	return string;
}
#endif

/* Bug 59544 */
/*
 * This function return the environment variable (see also java.c)
 *
 */
int ra_getEnvironmentVariable(char* name, char* buffer, int size) {
#ifdef _WIN32
	return GetEnvironmentVariable(name, buffer, size);
#else
	int len;
	char *currentValue = getenv(name);
	if (!currentValue) {
		return 0;
	}

	len = strlen(currentValue) + 1;

	if (size >= len) {
		memcpy(buffer, currentValue, len);
	}

	return len; /* Bug 68919 */
#endif
}

/*
 * Platform dependent code to check whether a process is alive
 */
BOOL isProcessAlive(PID pid) {
#ifdef _WIN32
	HANDLE handle;
	long status;
	handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
	if(handle) {
		if(GetExitCodeProcess(handle, &status)) {
			CloseHandle(handle); 
			if(status != STILL_ACTIVE) {
				return FALSE;
			}
			else {
				return TRUE;
			}
		}
		CloseHandle(handle); 
	}
	return FALSE;
#elif defined _AIX || defined MVS || defined _HPUX
	errno = 0;
	if(-1 == getpriority(PRIO_PROCESS, pid) && errno != 0) {
		return FALSE;
	}
	else {
		return TRUE;
	}
#elif defined __OS400__
	struct QP0W_PID_Data_T out;
	errno = 0;
	if(0 != Qp0wChkPid(pid, &out)) {
		return FALSE;
	}
	else {
		return TRUE;
	}
#else
	DIR *procDir;
	struct dirent *currentProcess;
	procDir = opendir("/proc");
	if(procDir) {
		for(currentProcess = readdir(procDir); currentProcess != NULL; currentProcess = readdir(procDir)) {
			if(pid == atoi(currentProcess->d_name)) {
				closedir(procDir); /* Bug 67736 */
				return TRUE;
			}
		}
		closedir(procDir);
	}
	else {
		/* ra_logServiceMessage(__FILE__, __LINE__,RA_INFORMATION, "Can't read process list errno = %d", errno); */ 
	}
	return FALSE;
#endif

}

/*
 * Native encoding to Unicode conversion functions
 */

/*
 * Returns the number of multi-byte char in the converted buffer
 * Arg 0: Pointer to the destination storage of the multi-byte buffer
 * Arg 1: Pointer to the source storage of the multi-byte buffer
 * Arg 2: Number of multi-byte in the buffer
 */
size_t native2unicode(char** out, char* in, size_t size_in) {
#if defined(_WIN32)
	int count;
	wchar_t* temp;

	count = mb2wc(&temp, in, size_in, GetACP());
	count = wc2mb(out, temp, count, CP_UTF8);
	ra_free(temp);

	return count;
#elif defined(__OS400__)
	/* UTF-8  is IBMCCSID0120800000000000000000000 */
	/* Native is IBMCCSID0000000000000000000000000 */
	return convert(out, in, size_in, "IBMCCSID0120800000000000000000000", "IBMCCSID0000000000000000000000000");
#elif defined(_HPUX)
	return convert(out, in, size_in, "utf8", nl_langinfo(CODESET)); /* HP-UX iconv_open() cannot take "UTF-8" */
#else
	return convert(out, in, size_in, "UTF-8", nl_langinfo(CODESET));
#endif
}

/*
 * Returns the number of multi-byte char in the converted buffer
 * Arg 0: Pointer to the destination storage of the multi-byte buffer
 * Arg 1: Pointer to the source storage of the multi-byte buffer
 * Arg 2: Number of multi-byte in the buffer
 */
size_t unicode2native(char** out, char* in, size_t size_in) {
	int count;
#if defined(_WIN32)
	wchar_t* temp;

	count = mb2wc(&temp, in, size_in, CP_UTF8);
	count = wc2mb(out, temp, count, GetACP());
	ra_free(temp);
#elif defined(__OS400__)
	/* UTF-8  is IBMCCSID0120800000000000000000000 */
	/* Native is IBMCCSID0000000000000000000000000 */
	return convert(out, in, size_in, "IBMCCSID0000000000000000000000000", "IBMCCSID0120800000000000000000000");
#elif defined(_HPUX)
	return convert(out, in, size_in, nl_langinfo(CODESET), "utf8"); /* HP-UX iconv_open() cannot take "UTF-8" */
#else
	return convert(out, in, size_in, nl_langinfo(CODESET), "UTF-8");
#endif

	return count;
}

/*
 * -----------------------------------------------------------------------------
 * WIN32 conversion functions
 * -----------------------------------------------------------------------------
 */
#ifdef _WIN32
/*
 * Returns the number of wchar
 * Arg 0: Pointer to the destination storage of the wchar buffer
 * Arg 1: Pointer to the source storage of the multi-byte char buffer
 * Arg 2: Number of wchar in the wchar buffer
 * Arg 3: Codepage for the conversion
 *
 */
int mb2wc(wchar_t** lpWideCharStr, char* lpMultiByteStr, int cbMultiByte, int cp) {
	int cchWideChar;

	/*
	 * Calculate the number of wchar required for the buffer
	 */
	cchWideChar = MultiByteToWideChar(
		cp,
		0,
		(LPSTR)lpMultiByteStr,
		cbMultiByte,
		NULL,
		0);

	*lpWideCharStr = (wchar_t*)ra_malloc(sizeof(wchar_t) * cchWideChar + 1);
	BZERO(*lpWideCharStr, sizeof(wchar_t) * cchWideChar + 1);

	return MultiByteToWideChar(
		cp,
		0,
		(LPSTR)lpMultiByteStr,
		cbMultiByte,
		*lpWideCharStr,
		cchWideChar);
}

/*
 * Returns the number of multi-byte char
 * Arg 0: Pointer to the destination storage of the multi-byte buffer
 * Arg 1: Pointer to the source storage of the wchar buffer
 * Arg 2: Number of multi-byte in the multi-byte buffer
 * Arg 3: Codepage for the conversion
 *
 */
int wc2mb(char** lpMultiByteStr, wchar_t* lpWideCharStr, int cchWideChar, int cp) {
	int cbMultiByte;

	/*
	 * Calculate the number of multibyte required for the buffer
	 */
	cbMultiByte = WideCharToMultiByte(
		cp,
		0,
		lpWideCharStr,
		cchWideChar,
		NULL,
		0,
		NULL,
		NULL);

	*lpMultiByteStr = (char*)ra_malloc(sizeof(char) * cbMultiByte + 1);
	BZERO(*lpMultiByteStr, sizeof(char) * cbMultiByte + 1);

	return WideCharToMultiByte(
		cp,
		0,
		lpWideCharStr,
		cchWideChar,
		(LPSTR)(*lpMultiByteStr),
		cbMultiByte,
		NULL,
		NULL);
}
#else
int convert(char** out, char* in, size_t size_in, char* to_cp, char* from_cp) {
	iconv_t cd; /* code page converter */
	char* inBuf_copy = 0; /* a copy of the input buffer, so that the original value is not modified */
	char* inBuf_start = 0; /* a pointer to the beginning of the inBuf_copy buffer used for free() */
	char* tempBuf = 0; /* a temporary buffer used to store the output of the conversion, allocated larger than required */
	char* tempBuf_start = 0; /* a pointer to the beginning of the tempBuf buffer used for free() */
	size_t outLen; /* Length of the allocated output buffer */
	size_t convLen; /* return value from iconv() */
	size_t tempLen; /* Length of the allocated output buffer, will actually be the numnber of bytes left in the buffer */
	size_t inLen_copy; /* a copy of the length of the input buffer */
#if _DEBUG2
	int i;
#endif

	setlocale(LC_CTYPE, "");
	cd = iconv_open(to_cp, from_cp); /* to, from */
#if _DEBUG2
		printf("DEBUG: CP(%s) -> CP(%s)\n", from_cp, to_cp);
#endif

#if defined(__OS400__)
	if(cd.return_value == -1) { /* iconv_t under OS/400 is a structure */
#else
	if(cd == (iconv_t)-1) {
#endif
#if _DEBUG2
		printf("DEBUG: Error calling iconv_open()\n");
#endif
		*out = 0; /* Bug 80588 */
		return 0;
	}

	inLen_copy = size_in; /* make a copy of the length */
	inBuf_copy = (char*)ra_malloc(sizeof(char) * inLen_copy); /* make a copy of the input buffer */
	memcpy(inBuf_copy, in, size_in);
	inBuf_start = inBuf_copy; /* mark the start of the input buffer */
#if _DEBUG2
	printf("DEBUG: inLen_copy = %d\n", inLen_copy);
	printf("DEBUG: inBuf_copy = ");
	for(i = 0; i < inLen_copy; i++) {
		printf("%c", inBuf_copy[i]);
	}
	printf("\n");
#endif

	tempLen = inLen_copy * 2; /* create the output buffer, larger than expected since we don't know the actual size yet */
	outLen = tempLen; /* bytes left and buffer size are the same at this point */
	tempBuf = (char*)ra_malloc(sizeof(char) * tempLen);
	tempBuf_start = tempBuf; /* mark the beginning of the output buffer */
	convLen = iconv(cd, &inBuf_copy, &inLen_copy, &tempBuf, &tempLen); /* perform the conversion */
	if(convLen == -1) {
#if _DEBUG2
		printf("DEBUG: Error running iconv(), errno = %d\n", errno);
		switch(errno) {
			case EILSEQ:
				printf("DEBUG: Invalid byte sequence at byte %d\n", inBuf_copy - inBuf_start);
				break;
			case E2BIG:
				printf("DEBUG: Ran out of space in the output buffer\n");
				break;
			case EINVAL:
				printf("DEBUG: Incomplete byte sequence at the end of the input buffer\n");
				break;
		}
#endif
		*out = 0; /* Bug 80588 */
		return 0; /* return 0 if it fails */
	}
#if _DEBUG2
	printf("DEBUG: Bytes left(tempLen) = %d\n", tempLen);
	printf("DEBUG: Output buffer(tempBuf_start) = ");
	for(i = 0; i < outLen - tempLen; i++) {
		printf("%c", tempBuf_start[i]);
	}
	printf("\n");
#endif

	*out = (char*)ra_malloc(sizeof(char) * (outLen - tempLen + 1)); /* create the output buffer with the actual size, adding a null */
	BZERO(*out, outLen - tempLen + 1);
	memcpy(*out, tempBuf_start, outLen - tempLen);  /* copy the contents from the temp buffer */
#if _DEBUG2
	printf("DEBUG: Copied buffer(out)\n");
	printf("DEBUG: Output buffer size = %d\n", outLen - tempLen);
#endif

	iconv_close(cd);

	ra_free(inBuf_start); /* free up working buffers */
	ra_free(tempBuf_start);

	return (outLen - tempLen);
}
#endif /* _WIN32 */
