/*******************************************************************************
 * Copyright (c) 2005, 2009 Intel 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
 *
 * Contributors:
 *    Andy Kaylor, Intel - Initial API and Implementation
 *    Kevin O'Leary, Intel - Implementation.
 *    IBM - Portions of processing code moved from older RAC (by Andy Kaylor)
 *
 * $Id: RACClientSupport.c,v 1.29 2009/08/26 14:59:58 jwest Exp $
 *
 *******************************************************************************/ 

/* 
 * This is mostly a duplication of the functions found in RACAgentSupport.c
 *   in the Agent compatibility transport layer, but are architecture works best
 *   if both TLs keep there own list.  Therefore this isn't being shared.  Also,
 *   the Agent compatibility TL requires some additional functions that are 
 *   removed from this version of the file
 */

#include "tptp/TPTPTypes.h"
#include "tptp/TPTPSupportTypes.h"
#include "tptp/TPTPSupportUtils.h"
#include "tptp/TransportSupport.h"
#include "tptp/BaseTLLog.h"
#include "tptp/compatibility/RACSupport.h"
#include "RACClientSupport.h"
#include "ClientCTL.h"
#include "java.h"
#include "secureServer.h"
#include "Connect2AC.h"

#ifdef _SOLARIS
	#include <netdb.h>
	#include <sys/socket.h>
#endif

#if defined(_AIX) || (defined(MVS) && defined(_LP64))
	#include <assert.h>
#endif

// Added for IPv6 support
#ifdef _WIN32
// TODO It's a workaround to get compiled on WIN IA32, it needs to be resolved.
	#define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
	#include <winsock2.h>
	#include <ws2tcpip.h>
#endif
 

#ifndef _WIN32
#include <signal.h>  // Used by ra_killProcess
#endif

/* Table for maintaining process information, including agents associated
   with the process */
static process_list_t *process_list;
static ra_string_t     _nodeUUID;

static void deleteAgentList(tl_state_data_t* stateData, agent_list_t *list);

/** GET_ACTIVE_PROCESS_LIST  ***************************************************
  * Retrieves the global process list the represents all the processes the
  * server knows about.
  */
process_list_t* ra_getActiveProcessList() {
	return process_list;
}

/** PROCESS_LIST_CREATE  *******************************************************
  * Allocates the memory required to create a process_list_t with no entries.
  * ie:  The head and tail are NULL
  */
process_list_t* ra_processListCreate() {
	process_list_t *list=(process_list_t*)tptp_malloc(sizeof(process_list_t));
	list->head=list->tail=NULL;
	list->process_count=0;
	return list;
}

/** INITIALIZE_DATA_STRUCTURES **************************************
  * Creates and initializes the global "process_list".  All the pointers
  * will be initialized correctly to allow error free iteration through
  * both the process list and the associated agent list for each of the
  * processes in the process list.
  */
void ra_initializeDataStructures() {
	ra_generateUUID(&_nodeUUID);
	process_list=ra_processListCreate();
//	ra_newAgentControllerConfiguration();
//	_network_list=ra_createNetworkList();
	ra_mutexCreate(&process_list->lock);
}


ra_string_t* getNodeUUID()
{
	return &_nodeUUID;
}

/** PROCESS_CREATE *************************************************************
  * Allocates the memory for a new process_t and appends this process to a
  * specific process list.  The new process_t structure will always be referenced
  * by list->process->tail.
  */
process_t* ra_processCreate(process_list_t *list) {
	/* Allocate the process_node, process, client list, and the agent list
	   for this process */
	process_t *process;
	process=(process_t*)tptp_malloc(sizeof(process_t));
	process->node=(process_list_node_t*)tptp_malloc(sizeof(process_list_node_t));


	//Provide the initial value... the startProcess command will need
	//to fill in this value.
	process->uuid.length = 0;
	process->uuid.data   = NULL;

	/* Initialize the application name */
	process->processName.length=0;
	process->processName.data=NULL;

	/* Initialize the agent count */
	process->active_agent_count=0;
	process->active_agents.head=process->active_agents.tail=NULL;
	process->waiting_agent_count=0;
	process->waiting_clients.head=process->waiting_clients.tail=NULL;

	/* Insert the process in the process_list */
	process->node->next=NULL;
	process->node->previous=list->tail;
	process->node->process=process;
	process->node->list=list;

	/* RKD:  To make the modification atomic we should use an atomic compare and swap here */
	list->tail=process->node;

	/* If this not the first entry we must set the link in the previous tail */
	if(process->node->previous) {
		process->node->previous->next=process->node;
	}
	else {
		list->head=process->node;
	}

	list->process_count++;

	return process;
}

/** AGENT_CREATE ***************************************************************
  * Allocates the memory for a new agent_t and appends this agent to a
  * specific process.  The new agent_t structure will always be referenced
  * by process->agents->->tail->agent.
  */
extern agent_t* ra_agentCreate(process_t *process,
							   BOOL active) {
	/* Allocate memory for both the agent and the holder for the agent
	   in the agent list structure */
	agent_list_t *list;
	agent_t *agent;
	agent=(agent_t*)tptp_malloc(sizeof(agent_t));
	agent->node=(agent_list_node_t*)tptp_malloc(sizeof(agent_list_node_t));

	agent->process=process;

	/* Initialize compatibility-specific fields */
	agent->agentID = -1;
	agent->agentToken = -1;

	/* This agent doesn't refer to a client yet */
	agent->client=NULL;
	agent->prev_client=NULL; /* 10000 */
	agent->attached=FALSE;
	agent->logging=FALSE;
	agent->IPCBufCreated=FALSE;
	agent->agentName.data=NULL;
	agent->agentName.length=0;
	agent->agentUUID.data=NULL;
	agent->agentUUID.length=0;
	agent->agentType.data=NULL;
	agent->agentType.length=0;
//	agent->connection=(ra_connection_t*)tptp_malloc(sizeof(ra_connection_t));
//	BZERO(agent->connection, sizeof(ra_connection_t));
	agent->pipe = (HANDLE)-1; 
//	agent->connection->type=RA_AGENTPIPE_CONNECTION;
//	agent->connection->target.agent=agent;

	/* Insert the agent in the appropiate agent list */
	agent->node->agent=agent;
	agent->node->next=NULL;

	if(active) {
		list=&process->active_agents;
		process->active_agent_count++;
		agent->node->list=&process->active_agents;
	}
	else {
		list=&process->waiting_clients;
		process->waiting_agent_count++;
		agent->node->list=&process->waiting_clients;
	}
	agent->node->previous=list->tail;

	/* RKD:  To make the modification atomic we should use an atomic compare and swap here */
	list->tail=agent->node;

	/* If this not the first entry we must set the link in the previous tail */
	if(agent->node->previous) {
		agent->node->previous->next=agent->node;
	}
	else {
		list->head=agent->node;
	}
	return agent;
}

/** PROCESS_FIND ***************************************************************
  * Find a process based upon its PID (key) in a specific process list.
  * @returns      NULL  - process is not in the list.
  *           otherwise - the address of the process_t structure
  */
process_t* ra_processFind(process_list_t *list,
						  PID processId) {
	process_list_node_t *current=list->head;

	while(current != NULL) {
		if(current->process->pid == processId) {
			return current->process;
		}
		current=current->next;
	}
	return NULL;
}

/** AGENT_FIND_BY_PROCESS ******************************************************
  * Find a agent based upon its name (key) in a specific process.
  * @returns      NULL  - agent is not associated with the process.
  *           otherwise - the address of the agent_t structure
  */
agent_t* ra_agentFindByProcess(process_t *process,
							   ra_string_t *agentName,
							   BOOL active) {
	agent_list_node_t *current;
	if(active) {
		current=process->active_agents.head;
	}
	else {
		current=process->waiting_clients.head;

	}

	while(current != NULL) {
		if(strncmp(current->agent->agentName.data, agentName->data, agentName->length) == 0) { /* Bug 80588 */
			return current->agent;
		}
		current=current->next;
	}
	return NULL;

}

BOOL findProcessAndAgent(
	PID pid,
	ra_string_t *agentName,
	BOOL active,
	process_list_t *list,
	agent_t **agent,
	process_t **process)
{
	*process = ra_processFind(list, pid);
	if (*process == NULL) {
		return FALSE;
	}
	*agent = ra_agentFindByProcess(*process, agentName, active);
	if (*agent == NULL) {
		return FALSE;
	}
	return TRUE;
}

/** AGENT_FIND_BY_UUID  ********************************************************
  *
  */
agent_t* ra_agentFindByUUID(process_list_t *list,
						   ra_string_t *agentUUID,
						   BOOL active) {

	process_list_node_t *processEntry=list->head;

	while(processEntry != NULL) {
		agent_list_node_t *current;
		if(active) {
			current=processEntry->process->active_agents.head;
		}
		else {
			current=processEntry->process->waiting_clients.head;

		}

		while(current != NULL) {
			if(strcmp(current->agent->agentUUID.data, agentUUID->data) == 0) {
				return current->agent;
			}
			current=current->next;
		}


		processEntry=processEntry->next;
	}
	return NULL;


}

/** AGENT_FIND_BY_AGENT_ID ******************************************************
  * This is a new function added for compatibiltiy support
  * It locates an agent structure in the process list given a tptp agent ID
  * @returns      NULL  - agent is not in the process list
  *           otherwise - the address of the agent_t structure
  */
agent_t* ra_agentFindByAgentID(process_list_t *list, unsigned int agentID ) {

	process_list_node_t *processEntry=list->head;

	while(processEntry != NULL) {
		agent_list_node_t *current=processEntry->process->active_agents.head;

		while(current != NULL) {
			if(current->agent->agentID == agentID){
				return current->agent;
			}
			current=current->next;
		}

		processEntry=processEntry->next;
	}
	return NULL;

}


/** FORWARD_MESSAGE  *************************************************************
  * Sends the message to the agent provided.  
  * AK - Note: The function signature is modified from the RAC code which 
  *               took a connection where we have an client connecion block.
  */
int ra_forwardMessage( ra_message_t *message, client_connection_block_t *client )
{
	int bytesWritten=0;
	unsigned long length;
	unsigned char *forwardBuffer;

	if(client == NULL) {
		return 0; /* Bug 62710 */
	}

	/* Copy the message to a buffer */
	length=ra_determineMessageLength(message);
	message->length=length;
	forwardBuffer=(unsigned char*)tptp_malloc(sizeof(char)*length);
	length=ra_writeMessageToBuffer(forwardBuffer, length, message);


	if ( client->connectionType == CCTL_NATIVE_SOCKET )	{
		bytesWritten = writeToSocket(client->sock,(char*)forwardBuffer, length);
		if(bytesWritten<0) {
			tptp_free( forwardBuffer );
			TPTP_LOG_WARNING_MSG( client->stateData, "Error writing to socket while sending message to client" );
			return FALSE;
		}
		else {
			TPTP_LOG_DEBUG_MSG1( client->stateData,  "Sent %d bytes to client", bytesWritten);
		}
	} else {
		/* call write method of java object */
		jmethodID writeMethod;
		jclass cls;
		JNIEnv *env;
		int byte=0;

		if ( 0 == ATTACH_THREAD(env) ) {

			/* Find the class object */
			cls=ENV(env)->GetObjectClass(ENVPARM(env) client->javaObj);

			writeMethod = getmthdid(env, cls, "write", "([BII)I");
			if (writeMethod) {
				jbyteArray jbarr;

				jbarr = ENV(env)->NewByteArray(ENVPARM(env) length);

				ENV(env)->SetByteArrayRegion(ENVPARM(env) jbarr, 0, length, (signed char *)forwardBuffer);


				/* Write the message to the write method of the java object */

				byte = ENV(env)->CallIntMethod(ENVPARM(env) client->javaObj, writeMethod, jbarr, 0, length);
			}
			else {
				ENV(env)->ExceptionClear(ENVPARM1(env));
				TPTP_LOG_SEVERE_MSG(client->stateData, "Could not get ID for method write");
				byte = -1;

			}
			if (byte == -1) {
				TPTP_LOG_WARNING_MSG(client->stateData, "Error sending message to client via java socket");
			}

			DETACH_THREAD();
		}
	}

	tptp_free( forwardBuffer );

	return TRUE;
}

/** PROCESS_REMOVE **************************************************************
  * Remove an process from a specific process list.
  */
void ra_processDestroy( tl_state_data_t* stateData, process_t *process ) {

	process_list_node_t *node=process->node;

	/* Change the links */
	if(node->previous && node->next) { /* Neither head nor tail */
		node->previous->next=node->next;
		node->next->previous=node->previous;
	}
	else if(node->next) { /* head */
		node->next->previous=NULL;
		node->list->head=node->next;
	}
	else if(node->previous) { /* tail */
		node->previous->next=NULL;
		node->list->tail=node->previous;
	}
	else if(node->list->head==node->list->tail) { /* only entry */
		node->list->tail=NULL;
		node->list->head=NULL;
	}
	/* decrement the process count */
	node->list->process_count--;

	/* Clean up the application name */
	ra_destroyRASTRING(&process->processName);
	process->processName.data=NULL;
	process->processName.length=0;


	/* We need to walk all the clients and agents, deleting each */
	TPTP_LOG_DEBUG_MSG1( stateData, "CCTL deleting active agent list for process %lu", process->pid );
	deleteAgentList(stateData, &process->active_agents);
	TPTP_LOG_DEBUG_MSG1( stateData, "CCTL deleting waiting agent list for process %lu", process->pid );
	deleteAgentList(stateData, &process->waiting_clients);


	tptp_free(process);
	tptp_free(node);
}

static void deleteAgentList( tl_state_data_t* stateData, agent_list_t *list ) {
	agent_list_node_t *current;

	if(!list) {
		return;
	}
	current=list->head;

	while(current != NULL) {
		agent_list_node_t *temp=current;

		TPTP_LOG_DEBUG_MSG2( stateData, "CCTL deleting agent (agentId=%ld, pid=%lu)", current->agent->agentID, current->agent->process->pid );

		notifyAgentOfProcessScrub( stateData, current->agent, current->agent->process->pid );
		ra_destroyRASTRING(&current->agent->agentName);
		ra_destroyRASTRING(&current->agent->agentUUID);
		ra_destroyRASTRING(&current->agent->agentType);
		tptp_free(current->agent);
		current->agent=NULL;
		current=current->next;
		tptp_free(temp);
	}
}

/** SCRUB_PROCESS  ************************************************************
  *
  */
BOOL scrubProcess(process_list_t *model, process_t *process, tl_state_data_t* stateData) {
	agent_list_node_t *agentNode;
	ra_message_t *message;
	ra_command_t *command;
	tl_control_connection_t*   connectionEntry;
	client_connection_block_t* ccb;

	if(!process) {
		return TRUE;
	}

// TODO:	ra_logServiceMessage(__FILE__, __LINE__,RA_INFORMATION, "Process %d exited", process->pid);
	TPTP_LOG_INFO_MSG1(stateData, "CCTL Scrubbing process %d", process->pid);

	message=ra_createMessage(RA_CONTROL_MESSAGE, 0);
	command=ra_addCommandToMessage(message, NULL);
	command->tag=RA_PROCESS_EXITED;
	command->info.process_exited.processId=process->pid;

	/* Inform all clients that the process has exited */
	agentNode=process->active_agents.head;
	while(agentNode != NULL) {
		if(agentNode->agent) {
			if(agentNode->agent->client) {
				/* bugzilla 64229 end */
				connectionEntry = (tl_control_connection_t*) tableGet(stateData->controlConnectionTable, agentNode->agent->client->clientID) ;
				if ( connectionEntry == NULL )
				{
					/* Unrecognized connection */
					/* TODO: Log an error */
					return -1;
				}
				ccb = (client_connection_block_t*) connectionEntry->implData;
				if ( ccb == NULL )
				{
					/* Missing client connection block */
					/* TODO: Log an error */
					return -1;
				}
				if (agentNode->agent->IPCBufCreated && agentNode->agent->logging) {
					waitForAgentDataFlush( stateData, agentNode->agent );
					stopAgentDataFlush(stateData, agentNode->agent);
				}
				
				command->info.agent_inactive.context = agentNode->agent->context;
				ra_forwardMessage(message, ccb);
				/* Remove agent from client's agent list */
				ra_disconnectAgentFromClient(agentNode->agent, ccb);  /* 214444 */
			}
			else if(agentNode->agent->prev_client) { /* Bug 84730 - tell any detached client about process exited */
				command->info.agent_inactive.context = agentNode->agent->context;
				connectionEntry = (tl_control_connection_t*) tableGet(stateData->controlConnectionTable, agentNode->agent->prev_client->clientID) ;
				if ( connectionEntry == NULL )
				{
					/* Unrecognized connection */
					/* TODO: Log an error */
					return -1;
				}
				ccb = (client_connection_block_t*) connectionEntry->implData;
				if ( ccb == NULL )
				{
					/* Missing client connection block */
					/* TODO: Log an error */
					return -1;
				}
				ra_forwardMessage(message, ccb);
			}
		}
		agentNode=agentNode->next;
	}

	agentNode=process->waiting_clients.head;
	while(agentNode != NULL) {
		if(agentNode->agent && agentNode->agent->prev_client) { 
			command->info.agent_inactive.context = agentNode->agent->context;
			connectionEntry = (tl_control_connection_t*) tableGet(stateData->controlConnectionTable, agentNode->agent->prev_client->clientID) ;
			if ( connectionEntry == NULL )
			{
				/* Unrecognized connection */
				/* TODO: Log an error */
				return -1;
			}
			ccb = (client_connection_block_t*) connectionEntry->implData;
			if ( ccb == NULL )
			{
				/* Missing client connection block */
				/* TODO: Log an error */
				return -1;
			}
			if (agentNode->agent->IPCBufCreated && agentNode->agent->logging ) {
				stopAgentDataFlush(stateData, agentNode->agent);
				//ra_logServiceMessage(__FILE__, __LINE__,RA_DEBUG, "Set data channel attach count to 1 for active agent %s", agentNode->agent->agentName.data);
			}
			ra_forwardMessage(message, ccb);
		}
		agentNode=agentNode->next;
	}

	/* kevin... what do we do here?
	if(process->console != -1) {
		ra_closeSocket(process->console); 
	}
	*/

	ra_destroyMessage(message, TRUE);
	ra_processDestroy(stateData, process); 
	return FALSE;
}

void ra_connectAgentToClient(agent_t *agent, client_connection_block_t *ccb) {

	agent_t *node;

	/* Allocate the space in the agent list for the client */
	node=(agent_t*)tptp_malloc(sizeof(agent_t));
	/*
	*/

	/* Set the agent info */
	agent->client = (client_t*)tptp_malloc( sizeof(client_t) );
	if ( agent->client != NULL )
	{
		agent->client->clientID = ccb->clientID;
	}
	if ( agent->prev_client != NULL )
	{
		tptp_free(agent->prev_client);
		agent->prev_client = NULL; /* 9693 */
	}
	agent->attached=TRUE;
	*node = *agent;

	tptp_list_add( &ccb->agents, node );
}

void ra_disconnectAgentFromClient(agent_t *agent, client_connection_block_t* ccb) {

	tptp_node_t* node;

	/* Disconnect the agent from the client */
	agent->prev_client = agent->client; /* 9693 */ /* 10000 */
	agent->client = NULL;

	/* Disconnect the client from the agent */
	for ( node = ccb->agents.head; node != NULL; node = node->next ) {
		agent_t* listAgent = (agent_t*)node->data;
		if ( isEqualString(listAgent->agentUUID.data, agent->agentUUID.data) ) {
			break;
		}
	}		
	if (node != NULL) {
		tptp_list_remove( &ccb->agents, node );
	}

	/* Mark this agent as un-attached */
	agent->attached=FALSE;
}

/** KILL PROCESS  ***************************************************
  *
  */
BOOL ra_killProcess(PID processId) {
#ifdef _WIN32
	HANDLE hProcess;

	hProcess=OpenProcess(PROCESS_TERMINATE, FALSE, processId);

	if(hProcess!=NULL) {
		return TerminateProcess(hProcess, 0);
	}
	return FALSE;
#else
	if(kill(processId, SIGKILL)) { /* 239668 */
		return FALSE;
	}
	return TRUE;
#endif
}

void ra_agentMakeActive(agent_t *agent) {
	agent_list_node_t *node;

	node=agent->node;

	if(&agent->process->waiting_clients==agent->node->list) {
		/* Remove node from current list */
		if(node->previous && node->next) { /* Neither head nor tail */
			node->previous->next=node->next;
			node->next->previous=node->previous;
		}
		else if(node->next) { /* head */
			node->next->previous=NULL;
			agent->process->waiting_clients.head=node->next;
		}
		else if(node->previous) { /* tail */
			node->previous->next=NULL;
			agent->process->waiting_clients.tail=node->previous;
		}
		else if(node->list->head==node->list->tail) { /* only entry */
			agent->process->waiting_clients.tail=NULL;
			agent->process->waiting_clients.head=NULL;
		}

		/* Add the node to the active list */
		node->next=NULL;
		node->previous=agent->process->active_agents.tail;
		agent->process->active_agents.tail=node;

		/* If this not the first entry we must set the link in the previous tail */
		if(node->previous) {
			node->previous->next=node;
		}
		else {
			agent->process->active_agents.head=node;
		}
		agent->process->active_agent_count++;
		agent->process->waiting_agent_count--;
/* 201349 begin */
		/* Make the agent's current list the active list */
		node->list = &agent->process->active_agents;
/* 201349 end */
	}
}

void ra_agentMakeInactive(agent_t *agent) {
	agent_list_node_t *node=agent->node;

	if(&agent->process->active_agents==agent->node->list) {
		/* Remove node from current list */
		if(node->previous && node->next) { /* Neither head nor tail */
			node->previous->next=node->next;
			node->next->previous=node->previous;
		}
		else if(node->next) { /* head */
			node->next->previous=NULL;
			agent->process->active_agents.head=node->next;
		}
		else if(node->previous) { /* tail */
			node->previous->next=NULL;
			agent->process->active_agents.tail=node->previous;
		}
		else if(agent->process->active_agents.head==agent->process->active_agents.tail) { /* only entry */
			agent->process->active_agents.tail=NULL;
			agent->process->active_agents.head=NULL;
		}

		/* Add the node to the waiting list */
		node->next=NULL;
		node->previous=agent->process->waiting_clients.tail;
		agent->process->waiting_clients.tail=node;

		/* If this not the first entry we must set the link in the previous tail */
		if(node->previous) {
			node->previous->next=node;
		}
		else {
			agent->process->waiting_clients.head=node;
		}
		agent->process->active_agent_count--;
		agent->process->waiting_agent_count++;
/* 201349 begin */
		/* Make the agent's current list the waiting list */
		node->list = &agent->process->waiting_clients;
/* 201349 end */
	}
}


int getClientIPAddr(client_connection_block_t* ccb, struct sockaddr_storage ** addr) {
	
    if (ccb->connectionType == CCTL_NATIVE_SOCKET) {
    	*addr = getPeerAddrOfSocket(ccb->sock);
    	
    }
    else if(ccb->connectionType == CCTL_JAVA_SOCKET) {
        JNIEnv *env;

        if(!ATTACH_THREAD(env)) {
            jclass clazz = fndclsid(env, INTERFACE_CLIENT_HANDLER);
            if(clazz) {
                jmethodID method = getmthdid(env, clazz, "getRemoteAddress", "()[B");
                if(method) {
                    jbyteArray result=(jbyteArray)ENV(env)->CallObjectMethod(ENVPARM(env) ccb->javaObj, method);
                    if(result) {
                        jbyte *elements;
                        jsize size = ENV(env)->GetArrayLength(ENVPARM(env) result);
                        elements = ENV(env)->GetByteArrayElements(ENVPARM(env) result, JNI_FALSE);
                        getSockAddrFromByteFormat(elements, size == 4 ? PF_INET : PF_INET6, addr );                        
                        
                    }
                }
			}
			DETACH_THREAD();
		}
	}

    return 0;
}

int getClientIP(client_connection_block_t* ccb, unsigned char *buffer, int *length) {
    //if(client->connection->type==RA_SOCKET_CONNECTION) { kevin we need to store this type info.
    if (ccb->connectionType == CCTL_NATIVE_SOCKET) {
    	
    	struct sockaddr_storage * addr;
    	unsigned char *value;
		int family = 0;
    	addr = getPeerAddrOfSocket(ccb->sock);
    	
    	if(addr == NULL) {
    		*length = 0;
    		return -1;
    	}
    	
    	getByteFormatFromSockAddr(addr, (void **)&value, &family);
    	
    	if(addr->ss_family == PF_INET) {
    		memcpy(buffer, value, sizeof(struct in_addr));
    		*length = sizeof(struct in_addr);
    		tptp_free(value);
    	} else  if(addr->ss_family == PF_INET6) {
    		memcpy(buffer, value, sizeof(struct in6_addr));
    		*length = sizeof(struct in6_addr);
    		tptp_free(value);
    	} else {
    		tptp_free(addr);
    		*length = 0;
    		return -1;
    	}
    	
    	tptp_free(addr);
    	
    }
    else if(ccb->connectionType == CCTL_JAVA_SOCKET) {
        JNIEnv *env;

        if(!ATTACH_THREAD(env)) {
            jclass clazz = fndclsid(env, INTERFACE_CLIENT_HANDLER);
            if(clazz) {
                jmethodID method = getmthdid(env, clazz, "getRemoteAddress", "()[B");
                if(method) {
                    jbyteArray result=(jbyteArray)ENV(env)->CallObjectMethod(ENVPARM(env) ccb->javaObj, method);
                    if(result) {
                        jbyte *elements;
                        jsize size = ENV(env)->GetArrayLength(ENVPARM(env) result);
                        elements = ENV(env)->GetByteArrayElements(ENVPARM(env) result, JNI_FALSE);
#ifdef _LP64
                        assert(size<=INT_MAX); 
#endif                        
                        *length=size;
                        memcpy(buffer, elements, *length);
                    }
                }
			}
			DETACH_THREAD();
		}
	}

    return 0;
}
#ifndef _WIN32
	#define INVALID_SOCKET -1
#endif

SOCKET openClientDataSocketAddr(struct sockaddr_storage *addr, int port) {
	char hostname[260];
	tptp_int32 rc = -1;
	SOCKET outSocket;
	
	hostname[0] = 0;

#if defined(_SOLARIS) || defined(MVS)
	int structSize = 0;
	if ( addr->ss_family == PF_INET ) {
		structSize = sizeof( struct sockaddr_in );
	} else {
		structSize = sizeof( struct sockaddr_in6 );
	}

	// Resolve the host name
	rc = getnameinfo((struct sockaddr *)addr, structSize, hostname, 260, NULL, 0, 0);
#else
		// Resolve the host name
	rc = getnameinfo((struct sockaddr *)addr, sizeof(struct sockaddr_storage), hostname, 260, NULL, 0, 0);
#endif

	if(rc == 0) {

		// Attempt to connect to the server by resolving the various addreses of the hostname
		connectToTCPServer(hostname, port, &outSocket);

		if(outSocket != INVALID_SOCKET) {
			return outSocket;
		}
	}

	// If we weren't able to resolve the host name, or couldn't succeed, try the IP address itself
	connectToTCPServerAddr(addr, port, &outSocket);

	return outSocket;

}

/** IPV4-ONLY */
SOCKET openClientDataSocket(tptp_int32 ip, tptp_int32 port)
{

	SOCKET sock = -1 ;
	tptp_int32 rc = -1;

	rc = connectToTCPServerIPv4M(ip, (unsigned short) port, &sock);

	if (rc == -1) {
		return -1;
	}

	return sock;
}
