/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at http://curl.haxx.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ***************************************************************************/ 
/* A multi-threaded example that uses pthreads and fetches 4 remote files at
 * once over HTTPS. The lock callbacks and stuff assume OpenSSL or GnuTLS
 * (libgcrypt) so far.
 *
 * OpenSSL docs for this:
 *   http://www.openssl.org/docs/crypto/threads.html
 * gcrypt docs for this:
 *   http://gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html
 */ 

#define USE_OPENSSL  

#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <curl/easy.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <syslog.h>
#include <pthread.h>

#define NUMT 2


#define TRUE 1
#define FALSE 0

# define SUCCESS 0
# define FAILURE -1

typedef enum
{
	PRIMARY_URL = 0,
	SECONDARY_URL
}
HOST_URL_ENUM;

typedef struct
{
	int		iTotSize;
	int		iWritten;
	char *	szMsg;
}
RESP_DATA_STYPE, * RESP_DATA_PTYPE;


#define CA_CERT_FILE	"ca-bundle.crt"

/* we have this global to let the callback get easy access to it */ 
static pthread_mutex_t *lockarray;

static struct curl_slist *	headers			= NULL;

static int initSSICURLHandle(CURL **, char*);
static void commonInit(CURL *, int);
static int sendDataToHost(CURL *, char *, int, char **, int *);
static size_t saveResponse(void *, size_t, size_t, void *);
static int initializeRespData(RESP_DATA_PTYPE);
static void waitForHostConnection(void);
static int chkConn(CURL *);

#ifdef USE_OPENSSL
#include <openssl/crypto.h>
static void lock_callback(int mode, int type, char *file, int line)
{
	(void)file;
	(void)line;
	if (mode & CRYPTO_LOCK) {
		pthread_mutex_lock(&(lockarray[type]));
	}
	else {
		pthread_mutex_unlock(&(lockarray[type]));
	}
}

static unsigned long thread_id(void)
{
	unsigned long ret;

	ret=(unsigned long)pthread_self();
	return(ret);
}

static void init_locks(void)
{
	int i;

	lockarray=(pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
			sizeof(pthread_mutex_t));
	for (i=0; i<CRYPTO_num_locks(); i++) {
		pthread_mutex_init(&(lockarray[i]),NULL);
	}

	CRYPTO_set_id_callback((unsigned long (*)())thread_id);
	CRYPTO_set_locking_callback((void (*)())lock_callback);
}

static void kill_locks(void)
{
	int i;

	CRYPTO_set_locking_callback(NULL);
	for (i=0; i<CRYPTO_num_locks(); i++)
		pthread_mutex_destroy(&(lockarray[i]));

	OPENSSL_free(lockarray);
}
#endif

#ifdef USE_GNUTLS
#include <gcrypt.h>
#include <errno.h>

GCRY_THREAD_OPTION_PTHREAD_IMPL;

void init_locks(void)
{
	gcry_control(GCRYCTL_SET_THREAD_CBS);
}

#define kill_locks()
#endif

/*
 * ============================================================================
 * Function Name: commonInit
 *
 * Description	: This function contains the code for common initialization of
 * 					all the three handles needed for communication with the PWC
 *
 * Input Params	: CURL * handle	-> curl handle that needs to be configured
 *
 * Output Params: void
 * ============================================================================
 */
static void commonInit(CURL * handle, int certValdReq)
{

	printf("%d: %s: --- enter ---\n", pthread_self(), pthread_self(), __FUNCTION__);


	/* Set the NO SIGNAL option, This option is very important to set in case
	 * of multi-threaded applications like ours, because otherwise the libcurl
	 * uses signal handling for the communication and that causes the threads
	 * to go crazy and even crash. Fix done for issue 1659 (Church of LDS AmDocs
	 * Case# 130826-3983) */
	curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L);

	/* Set the HTTP post option */
	curl_easy_setopt(handle, CURLOPT_POST, 1L);

	/* Add the headers */
	curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers);

/*#ifdef DEBUG
	/* Add the debug function
	curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, curlDbgFunc);
#endif*/

	if (certValdReq == TRUE)
	{
		printf("%d: %s: Url starts with https. Doing certificate validation\n", pthread_self(), __FUNCTION__);


		curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 1L);
		curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 2L);
	}

	/* Set the CA certificate */
	curl_easy_setopt(handle, CURLOPT_CAINFO, CA_CERT_FILE);

	/* Set the write function */
	curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, saveResponse);

	/* Set the detection as TRUE for HTTP errors */
	curl_easy_setopt(handle, CURLOPT_FAILONERROR, TRUE);

	printf("%d: %s: --- returning ---\n", pthread_self(), pthread_self(), __FUNCTION__);

	return;
}




/*
 * ============================================================================
 * Function Name: initSSICURLHandle
 *
 * Description	:
 *
 * Input Params	:
 *
 * Output Params: SUCCESS / FAILURE
 * ============================================================================
 */
static int initSSICURLHandle(CURL ** handle, char* pszHostUrl)
{
	int					rv				= SUCCESS;
	char				szTmpURL[100]	= "";
	CURL *				locHandle		= NULL;
	int					certValdReq 	= TRUE;

	printf("%d: %s: --- enter ---\n", pthread_self(), __FUNCTION__);

	while(1)
	{
		/* Initialize the handle using the CURL library */
		locHandle = curl_easy_init();
		if(locHandle == NULL)
		{
			printf("%d: %s: Curl initialization for handle failed\n",
					pthread_self(), __FUNCTION__);
			rv = FAILURE;
			break;
		}

		curl_easy_setopt(locHandle, CURLOPT_URL, pszHostUrl);

		printf("%d: %s: Setting PWC URL = [%s]\n", pthread_self(), __FUNCTION__, pszHostUrl);


		/* Set the connection timeout */
		curl_easy_setopt(locHandle, CURLOPT_CONNECTTIMEOUT, 10);

		/* Set the total timeout */

		curl_easy_setopt(locHandle, CURLOPT_TIMEOUT, 20);


		/* Set the other common features */
		commonInit(locHandle, certValdReq);
		*handle = locHandle;

		break;
	}

	printf("%d: %s: Returning [%d]\n", pthread_self(), __FUNCTION__, rv);


	return rv;
}


static void postDataToUrl()
{
	int			rv;
	char*		szHostUrl		= "URL1";
	CURL *		curlHandle		= NULL;
	char		req[2560]		= "Message";
	int			reqSize			= strlen(req);
	char*		resp			= NULL;
	int			respSize		= 0;


	rv = initSSICURLHandle(&curlHandle, szHostUrl);

	rv = sendDataToHost(curlHandle, req, reqSize, &resp, &respSize);
	if(rv != SUCCESS)
	{
		printf("%d: %s: Failed to post data to server\n", pthread_self(), __FUNCTION__);
	}

	if (resp != NULL)
	{
		printf("%d: %s Response Received: %s \n", pthread_self(), __FUNCTION__, resp);
		free(resp);
		resp = NULL;
	}

	curl_easy_cleanup(curlHandle);
}

static void *pull_one_url(void *i)
{
	int iOption = *(int*)i;
	/*  CURL *curl;

  curl = curl_easy_init();
  curl_easy_setopt(curl, CURLOPT_URL, url);
   this example doesn't verify the server's certificate, which means we
     might be downloading stuff from an impostor
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
  curl_easy_perform(curl);  ignores error
  curl_easy_cleanup(curl);*/
	while(1)
	{
		switch(iOption)
		{
		case 0:
			postDataToUrl();
			break;

		case 1:
			waitForHostConnection();
			break;
		}
		sleep(3);
	}

	return NULL;
}

/*
 * ============================================================================
 * Function Name: waitForHostConnection
 *
 * Description	:
 *
 * Input Params	:
 *
 * Output Params:
 * ============================================================================
 */
static void waitForHostConnection()
{
	int 		iRetVal 	          = SUCCESS;

	while(1)
	{
		if(isHostConnected() == TRUE)
		{
			printf( "%d: %s: Host connection is available\n",pthread_self(), __FUNCTION__);
		}
		else
		{
			printf( "%d: %s: Host connection is not available, checking once more...\n",pthread_self(), __FUNCTION__);
		}

		sleep(3);
	}
}

/*
 * ============================================================================
 * Function Name: isHostConnected
 *
 * Description	:
 *
 * Input Params	: none
 *
 * Output Params: TRUE / FALSE
 * ============================================================================
 */
int isHostConnected()
{
	int	bRv				= TRUE;

	printf( "%d: %s: --- enter ---\n", pthread_self(), __FUNCTION__);


	if(SUCCESS == checkHostConn())
	{
		bRv = TRUE;
	}
	else
	{
		bRv = FALSE;
	}

	printf( "%d: %s: Returning [%s]\n", pthread_self(), __FUNCTION__,
			(bRv == TRUE)? "TRUE" : "FALSE");


	return  bRv;
}

/*
 * ============================================================================
 * Function Name: checkHostConn
 *
 * Description	:
 *
 * Input Params	:
 *
 * Output Params: SUCCESS / FAILURE
 * ============================================================================
 */
int checkHostConn()
{
	int			rv				= SUCCESS;
	int			iCnt			= 0;
	static int	host			= PRIMARY_URL;
	CURL *		curlHandle		= NULL;
	char*		szHostUrl		= "url1";
#ifdef DEBUG
	char		szDbgMsg[512]	= "";
#endif

	printf( "%d: %s: --- enter ---\n", pthread_self(), __FUNCTION__);


	while(iCnt < 2)
	{
		rv = initSSICURLHandle(&curlHandle, szHostUrl);

		if(rv == SUCCESS)
		{
			/* Curl handler initialized successfully
			 * Checking connection */
			rv = chkConn(curlHandle);
			if(rv != SUCCESS)
			{
				printf( "%d: %s: FAILED to check Host connection\n",
						pthread_self(), __FUNCTION__);
			}
			else
			{
				printf( "%d: %s: Host connection available\n", pthread_self(), __FUNCTION__);
			}
		}

		if(rv == SUCCESS)
		{
			printf( "%d: %s: Breaking from the loop\n", pthread_self(), __FUNCTION__);

			break;
		}

		/* If the first host is not working then try the next host */
		host ^= 1;
		iCnt++;

		printf( "%d: %s: Trying again..\n", pthread_self(), __FUNCTION__);
	}

	printf( "%d: %s: Returning [%d]\n", pthread_self(), __FUNCTION__, rv);


	return rv;
}

/*
 * ============================================================================
 * Function Name: chkConn
 *
 * Description	:
 *
 * Input Params	:
 *
 *
 * Output Params: SUCCESS / FAILURE
 * ============================================================================
 */
static int chkConn(CURL * curlHandle)
{
	int				rv				= SUCCESS;
	long			lCode			= 0L;
#ifdef DEBUG
	char			szDbgMsg[256]	= "";
#endif

	printf( "%d: %s: --- enter ---\n", pthread_self(), __FUNCTION__);

	while(1)
	{
		curl_easy_setopt(curlHandle, CURLOPT_POST, 0L);
		curl_easy_setopt(curlHandle, CURLOPT_NOBODY, 1);
		curl_easy_setopt(curlHandle, CURLOPT_FOLLOWLOCATION, 1);

		rv = curl_easy_perform(curlHandle);
		if(rv == CURLE_OK)
		{
			printf( "%d: %s: Perform SUCCESS\n", pthread_self(), __FUNCTION__);

		}
		else
		{
			printf( "%d: %s: Return Value from PERFORM = [%d]\n",
					pthread_self(), __FUNCTION__, rv);

		}

		rv = curl_easy_getinfo(curlHandle, CURLINFO_RESPONSE_CODE, &lCode);

		printf( "%d: Return Value RESPONSE CODE = [%d], [%ld]\n",
				pthread_self(), __FUNCTION__, rv, lCode);


		if(rv == 0 && lCode == 200)
		{
			printf( "%d: Got Successful respcode from host\n",
					pthread_self(), __FUNCTION__);


			rv = SUCCESS;
		}
		else
		{
			printf( "%d: Didnt get the good resp code from host\n"
					, pthread_self(), __FUNCTION__);
			rv = FAILURE;
		}

		break;
	}

	if(curlHandle != NULL)
	{
		curl_easy_cleanup(curlHandle);
	}

	printf( "%d: %s: Returning [%d]\n", pthread_self(), __FUNCTION__, rv);

	return rv;
}

int main(int argc, char **argv)
{
	pthread_t tid[NUMT];
	int i;
	int error;
	(void)argc; /* we don't use any arguments in this example */
	(void)argv;

	/* Add data to the headers */
	headers = curl_slist_append(headers, "Content-Type:text/xml");

	/* Must initialize libcurl before any threads are started */
	curl_global_init(CURL_GLOBAL_ALL);

	init_locks();

	for(i=0; i< NUMT; i++) {
		error = pthread_create(&tid[i],
				NULL, /* default attributes please */
				pull_one_url,
				(void *)(&i));
		if(0 != error)
			fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
		else
			fprintf(stderr, "Thread %d, gets %d\n", i, tid[i]);
	}

	/* now wait for all threads to terminate */
	for(i=0; i< NUMT; i++) {
		error = pthread_join(tid[i], NULL);
		fprintf(stderr, "Thread %d terminated\n", i);
	}

	kill_locks();

	return 0;
}


/*
 * ============================================================================
 * Function Name: sendDataToHost
 *
 * Description	: This function sends the XML data to the PWC server, using the
 * 					appropriate CURL handle.
 *
 * Input Params	:
 * 				PWC_URL_TYPE_ENUM urlType -> constant telling which handle to
 * 												use
 * 				unsigned char *	  data	  -> the XML data that needs to be sent
 * 				int				  size	  -> size of the data
 *
 * Output Params: SUCCESS / FAILURE
 * ============================================================================
 */
static int sendDataToHost(CURL * curlHandle, char * req, int reqSize,
												char ** resp, int * respSize)
{
	int				rv				   = SUCCESS;
	char			szCurlErrBuf[4096] = "";
	RESP_DATA_STYPE	stRespData;

	printf("%d: %s: --- enter ---\n", pthread_self(), __FUNCTION__);

	while(1)
	{
		/* Initialize the response data */
		rv = initializeRespData(&stRespData);
		if(rv != SUCCESS)
		{
			printf("%d: %s: Initialization of response data FAILED\n"
																, pthread_self(), __FUNCTION__);



			break;
		}

		/* Set some curl library options before sending the data */
		curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &stRespData);
		curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDS, (void *) req);
		curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDSIZE, reqSize);
		curl_easy_setopt(curlHandle, CURLOPT_ERRORBUFFER, szCurlErrBuf);

		printf("%d: %s: Posting the data to the server\n", pthread_self(), __FUNCTION__);



		/* post the data to the server */
		rv = curl_easy_perform(curlHandle);

		printf("%d: %s: curl_easy_perform done, rv = %d\n", pthread_self(), __FUNCTION__, rv);



		if(rv == CURLE_OK)
		{
			*resp = stRespData.szMsg;
			*respSize = stRespData.iWritten;

			printf("%d: Data Posted Succesfully\n");

			printf("%d: %s: Response Len = [%d]\n", pthread_self(), __FUNCTION__,
														stRespData.iWritten);


		}
		else
		{
			switch(rv)
			{
			case CURLE_UNSUPPORTED_PROTOCOL: /* 1 */
				/*
				 * The URL you passed to libcurl used a protocol that this libcurl does not support.
				 * The support might be a compile-time option that you didn't use,
				 * it can be a misspelled protocol string or just a protocol libcurl has no code for.
				 */
				printf("%d: %s: protocol not supported by library\n",
																pthread_self(), __FUNCTION__);

				break;

			case CURLE_URL_MALFORMAT: /* 3 */
				/*
				 * The URL was not properly formatted.
				 */
				printf("%d: %s: URL not properly formatted\n",
																pthread_self(), __FUNCTION__);

				break;

			case CURLE_COULDNT_RESOLVE_HOST: /* 6 */
				/*
				 * Couldn't resolve host. The given remote host was not resolved.
				 */
				printf("%d: %s: Couldnt resolve server's address\n", pthread_self(), __FUNCTION__);

				break;

			case CURLE_COULDNT_CONNECT: /* 7 */
				/*
				 * Failed to connect() to host or proxy.
				 */
				printf("%d: %s: Failed to connect server\n",
																pthread_self(), __FUNCTION__);

				break;

			case CURLE_HTTP_RETURNED_ERROR: /* 22 */
				/*
				 * This is returned if CURLOPT_FAILONERROR is set TRUE
				 * and the HTTP server returns an error code that is >= 400.
				 */
				printf("%d: %s: Got HTTP error while posting\n",
																pthread_self(), __FUNCTION__);

				break;

			case CURLE_WRITE_ERROR: /* 23 */
				/*
				 * An error occurred when writing received data to a local file,
				 * or an error was returned to libcurl from a write callback.
				 */
				printf("%d: %s: Failed to save the response data\n",
																pthread_self(), __FUNCTION__);



				rv = FAILURE;
				break;

			case CURLE_OUT_OF_MEMORY: /* 27 */
				/*
				 * A memory allocation request failed.
				 * This is serious badness and things are severely screwed up if this ever occurs.
				 */
				printf("%d: %s: Facing memory shortage \n",
																pthread_self(), __FUNCTION__);



				rv = FAILURE;
				break;

			case CURLE_OPERATION_TIMEDOUT: /* 28 */
				/*
				 * Operation timeout.
				 * The specified time-out period was reached according to the conditions.
				 */
				printf("%d: %s: Timeout happened while receiving\n",
																pthread_self(), __FUNCTION__);

				break;

			case CURLE_SSL_CONNECT_ERROR: /* 35 */
				/*
				 * A problem occurred somewhere in the SSL/TLS handshake.
				 *
				 */
				printf("%d: %s: SSL/TLS Handshake FAILED\n",
																pthread_self(), __FUNCTION__);

				break;

			case CURLE_PEER_FAILED_VERIFICATION: /* 51 */
				/*
				 * The remote server's SSL certificate or SSH md5 fingerprint was deemed not OK.
				 */
				printf("%d: %s: Server's SSL certificate verification FAILED\n",
							pthread_self(), __FUNCTION__);

				break;

			case CURLE_SEND_ERROR: /* 55 */
				/*
				 * Failed sending network data.
				 */
				printf("%d: %s: Failed to post the request data\n", pthread_self(), __FUNCTION__);

				break;

			case CURLE_RECV_ERROR: /* 56 */
				/*
				 * Failure with receiving network data.
				 */
				printf("%d: %s: Failed to receive the response\n",
																pthread_self(), __FUNCTION__);

				break;

			case CURLE_SSL_CACERT: /* 60 */
				/*
				 * Peer certificate cannot be authenticated with known CA certificates.
				 */
				printf("%d: %s: Couldnt authenticate peer certificate\n",
																pthread_self(), __FUNCTION__);

				break;

			case CURLE_SSL_CACERT_BADFILE: /* 77 */
				/*
				 * Problem with reading the SSL CA cert (path? access rights?)
				 */
				printf("%d: %s: Cant find SSL CA sertificate [%s]\n",
												pthread_self(), __FUNCTION__, CA_CERT_FILE);

				break;

			default:
				printf("%d: %s: Error [%d] occured while posting\n",
															pthread_self(), __FUNCTION__, rv);

				break;
			}

			if(stRespData.szMsg != NULL)
			{
				free(stRespData.szMsg);
				stRespData.szMsg = NULL;
			}


			printf("%d: %s: Lib Curl Error [%s]\n",pthread_self(), __FUNCTION__, szCurlErrBuf);
		}

		break;
	}

	printf("%d: %s: Returning [%d]\n", pthread_self(), __FUNCTION__, rv);


	return rv;
}


/*
 * ============================================================================
 * Function Name: initializeRespData
 *
 * Description	: This function is used for the initial setting of the response
 * 					data structure which would then be used for storing XML
 * 					response retrieved from the server being contacted.
 *
 * Input Params	: RESP_DATA_PTYPE stRespPtr -> pointer to response structure
 *
 * Output Params: SUCCESS / FAILURE
 * ============================================================================
 */
static int initializeRespData(RESP_DATA_PTYPE stRespPtr)
{
	int		rv				= SUCCESS;
	char *	cTmpPtr			= NULL;


	printf("%d: %s: --- enter ---\n", pthread_self(), __FUNCTION__);


	cTmpPtr = (char *) malloc(4096 * sizeof(char));
	if(cTmpPtr != NULL)
	{
		/* Initialize the memory */
		memset(cTmpPtr, 0x00, 4096 * sizeof(char));
		memset(stRespPtr, 0x00, sizeof(RESP_DATA_STYPE));

		/* Assign the data */
		stRespPtr->iTotSize = 4096;
		stRespPtr->iWritten = 0;
		stRespPtr->szMsg	= cTmpPtr;
	}
	else
	{
		printf("%d: %s: Memory allocation FAILED\n", pthread_self(), __FUNCTION__);



		rv = FAILURE;
	}

	printf("%d: %s: Returning [%d]\n", pthread_self(), __FUNCTION__, rv);



	return rv;
}


/*
 * ============================================================================
 * Function Name: saveResponse
 *
 * Description	: This function performs the job of saving the XML response
 * 					coming from the server into a buffer provided as parameter.
 * 					This function is passed to the CURL library, and the
 * 					library would call this function, not us.
 *
 * Input Params	:
 * 					void * ptr -> pointer to the data that needs to be copied
 * 					size_t size-> size of one element of data
 * 					size_t cnt -> count of data members
 * 					void * des -> our buffer where the response is saved
 *
 * Output Params: totLen -> length of data saved
 * ============================================================================
 */
static size_t saveResponse(void * ptr, size_t size, size_t cnt, void * des)
{
	int				rv				= SUCCESS;
	int				iSizeLeft		= 0;
	int				totLen			= 0;
	int				iReqdLen		= 0;
	char *			cTmpPtr			= NULL;
	RESP_DATA_PTYPE	respPtr			= NULL;


	printf("%d: %s: --- enter ---\n", pthread_self(), __FUNCTION__);

	while(1)
	{

		respPtr = (RESP_DATA_PTYPE) des;
		totLen = size * cnt;
		iSizeLeft = respPtr->iTotSize - respPtr->iWritten;

		if(totLen > iSizeLeft)
		{
			iReqdLen = (respPtr->iTotSize + totLen - iSizeLeft) + 1/* one extra buffer for NULL at the end for safety purpose*/;

			cTmpPtr = (char *) realloc(respPtr->szMsg, iReqdLen);
			if(cTmpPtr == NULL)
			{
				printf("%d: %s: Reallocation of memory FAILED\n",
						pthread_self(), __FUNCTION__);



				rv = FAILURE;
				break;
			}

			memset(cTmpPtr + respPtr->iWritten, 0x00, iReqdLen - respPtr->iWritten);

			respPtr->iTotSize = iReqdLen;
			respPtr->szMsg = cTmpPtr;
		}

		memcpy(respPtr->szMsg + respPtr->iWritten, ptr, totLen);
		respPtr->iWritten += totLen;

		rv = totLen;

		break;
	}

	printf("%d: %s: Returning [%d]\n", pthread_self(), __FUNCTION__, rv);



	return rv;
}
