Exemple #1
0
void cleanup_handle(void *obj)
{
	WINPR_THREAD* thread = (WINPR_THREAD*) obj;
	int rc = pthread_mutex_destroy(&thread->mutex);

	if (rc)
		WLog_ERR(TAG, "failed to destroy mutex [%d] %s (%d)",
				rc, strerror(errno), errno);

	if (thread->pipe_fd[0])
		close(thread->pipe_fd[0]);

	if (thread->pipe_fd[1])
		close(thread->pipe_fd[1]);

	if (thread_list && ListDictionary_Contains(thread_list, &thread->thread))
		ListDictionary_Remove(thread_list, &thread->thread);

#if defined(WITH_DEBUG_THREADS)

	if (thread->create_stack)
		winpr_backtrace_free(thread->create_stack);

	if (thread->exit_stack)
		winpr_backtrace_free(thread->exit_stack);

#endif
	free(thread);
}
Exemple #2
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
static UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
{
	void* key;
	key = (void*)(size_t) irp->CompletionId;
	ListDictionary_Remove(smartcard->rgOutstandingMessages, key);
	return irp->Complete(irp);
}
Exemple #3
0
void remove_callback_by_name(const char *name, void *context)
{
	if (!cb_dict)
	{
		DEBUG_WARN("trying to remove '%s', but function list does not exist.",
				   name);
		return;
	}

	if (!ListDictionary_Contains(cb_dict, (void *)name))
	{
		DEBUG_WARN("trying to remove '%s', which is not in function list.",
				   name);
		return;
	}

	DEBUG_DVC("Removing '%s' from function list.", name);
	ListDictionary_Remove(cb_dict, (void *)name);

	if (ListDictionary_Count(cb_dict) < 1)
	{
		DEBUG_DVC("Function list is empty, freeing resources.");
		ListDictionary_Free(cb_dict);
		cb_dict = NULL;
	}

	dump_callbacks();
}
void encomsp_remove_init_handle_data(void* pInitHandle)
{
	ListDictionary_Remove(g_InitHandles, pInitHandle);
	if (ListDictionary_Count(g_InitHandles) < 1)
	{
		ListDictionary_Free(g_InitHandles);
		g_InitHandles = NULL;
	}
}
Exemple #5
0
void devman_unregister_device(DEVMAN* devman, void* key)
{
	DEVICE* device;

	device = (DEVICE*) ListDictionary_Remove(devman->devices, key);

	if (device)
		devman_device_free(device);
}
Exemple #6
0
void freerdp_channel_remove_init_handle_data(rdpChannelHandles* handles, void* pInitHandle)
{
	ListDictionary_Remove(handles->init, pInitHandle);

	if (ListDictionary_Count(handles->init) < 1)
	{
		ListDictionary_Free(handles->init);
		handles->init = NULL;
	}
}
void encomsp_remove_open_handle_data(DWORD openHandle)
{
	void* pOpenHandle = (void*) (size_t) openHandle;
	ListDictionary_Remove(g_OpenHandles, pOpenHandle);
	if (ListDictionary_Count(g_OpenHandles) < 1)
	{
		ListDictionary_Free(g_OpenHandles);
		g_OpenHandles = NULL;
	}
}
Exemple #8
0
void freerdp_channel_remove_open_handle_data(rdpChannelHandles* handles, DWORD openHandle)
{
	void* pOpenHandle = (void*)(size_t) openHandle;
	ListDictionary_Remove(handles->open, pOpenHandle);

	if (ListDictionary_Count(handles->open) < 1)
	{
		ListDictionary_Free(handles->open);
		handles->open = NULL;
	}
}
Exemple #9
0
void freerds_update_frame_acknowledge(rdpContext* context, UINT32 frameId)
{
	SURFACE_FRAME* frame;
	rdsConnection* connection = (rdsConnection*) context;

	frame = (SURFACE_FRAME*) ListDictionary_GetItemValue(connection->FrameList, (void*) (size_t) frameId);

	if (frame)
	{
		ListDictionary_Remove(connection->FrameList, (void*) (size_t) frameId);
		free(frame);
	}
}
Exemple #10
0
BOOL CryptUnprotectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags)
{
	BYTE* pPlainText = NULL;
	size_t cbOut, cbFinal;
	WINPR_CIPHER_CTX* dec = NULL;
	WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock = NULL;

	if (dwFlags != CRYPTPROTECTMEMORY_SAME_PROCESS)
		return FALSE;

	if (!g_ProtectedMemoryBlocks)
		return FALSE;

	pMemBlock = (WINPR_PROTECTED_MEMORY_BLOCK*) ListDictionary_GetItemValue(g_ProtectedMemoryBlocks, pData);

	if (!pMemBlock)
		goto out;

	cbOut = pMemBlock->cbData + 16 - 1;

	pPlainText = (BYTE*) malloc(cbOut);

	if (!pPlainText)
		goto out;

	if ((dec = winpr_Cipher_New(WINPR_CIPHER_AES_256_CBC, WINPR_DECRYPT,
				    pMemBlock->key, pMemBlock->iv)) == NULL)
		goto out;
	if (!winpr_Cipher_Update(dec, pMemBlock->pData, pMemBlock->cbData, pPlainText, &cbOut))
		goto out;
	if (!winpr_Cipher_Final(dec, pPlainText + cbOut, &cbFinal))
		goto out;
	winpr_Cipher_Free(dec);

	CopyMemory(pMemBlock->pData, pPlainText, pMemBlock->cbData);
	SecureZeroMemory(pPlainText, pMemBlock->cbData);
	free(pPlainText);

	ListDictionary_Remove(g_ProtectedMemoryBlocks, pData);

	free(pMemBlock);

	return TRUE;

out:
	free(pPlainText);
	free(pMemBlock);
	winpr_Cipher_Free(dec);
	return FALSE;
}
static void drdynvc_remove_open_handle_data(DWORD openHandle)
{
	void* pOpenHandle = (void*) (size_t) openHandle;

	if (!g_OpenHandles)
		return;

	ListDictionary_Remove(g_OpenHandles, pOpenHandle);

	if (ListDictionary_Count(g_OpenHandles) < 1)
	{
		ListDictionary_Free(g_OpenHandles);
		g_OpenHandles = NULL;
	}
}
Exemple #12
0
/**
 * Function description
 *
 * @return 0 on success, otherwise a Win32 error code
 */
static UINT drive_process_irp_close(DRIVE_DEVICE* drive, IRP* irp)
{
	void* key;
	DRIVE_FILE* file;
	file = drive_get_file_by_id(drive, irp->FileId);
	key = (void*)(size_t) irp->FileId;

	if (!file)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
	}
	else
	{
		ListDictionary_Remove(drive->files, key);
		drive_file_free(file);
	}

	Stream_Zero(irp->output, 5); /* Padding(5) */
	return irp->Complete(irp);
}
Exemple #13
0
BOOL CryptUnprotectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags)
{
	BYTE* pPlainText;
	int cbOut, cbFinal;
	WINPR_PROTECTED_MEMORY_BLOCK* pMemBlock;

	if (dwFlags != CRYPTPROTECTMEMORY_SAME_PROCESS)
		return FALSE;

	if (!g_ProtectedMemoryBlocks)
		return FALSE;

	pMemBlock = (WINPR_PROTECTED_MEMORY_BLOCK*) ListDictionary_GetItemValue(g_ProtectedMemoryBlocks, pData);

	if (!pMemBlock)
		return FALSE;

	/* AES Decryption */

	cbOut = pMemBlock->cbData + AES_BLOCK_SIZE - 1;
	pPlainText = (BYTE*) malloc(cbOut);

	EVP_DecryptInit_ex(&(pMemBlock->dec), NULL, NULL, NULL, NULL);
	EVP_DecryptUpdate(&(pMemBlock->dec), pPlainText, &cbOut, pMemBlock->pData, pMemBlock->cbData);
	EVP_DecryptFinal_ex(&(pMemBlock->dec), pPlainText + cbOut, &cbFinal);

	CopyMemory(pMemBlock->pData, pPlainText, pMemBlock->cbData);
	SecureZeroMemory(pPlainText, pMemBlock->cbData);
	free(pPlainText);

	ListDictionary_Remove(g_ProtectedMemoryBlocks, pData);

	/* AES Cleanup */

	EVP_CIPHER_CTX_cleanup(&(pMemBlock->enc));
	EVP_CIPHER_CTX_cleanup(&(pMemBlock->dec));

	free(pMemBlock);

	return TRUE;
}
static UINT32 smartcard_ReleaseContext_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation, Context_Call* call)
{
	UINT32 status;
	Long_Return ret;

	status = ret.ReturnCode = SCardReleaseContext(operation->hContext);

	if (ret.ReturnCode == SCARD_S_SUCCESS)
	{
		SMARTCARD_CONTEXT* pContext;
		void* key = (void*) (size_t) operation->hContext;

		pContext = (SMARTCARD_CONTEXT*) ListDictionary_Remove(smartcard->rgSCardContextList, key);

		smartcard_context_free(pContext);
	}

	smartcard_trace_long_return(smartcard, &ret, "ReleaseContext");

	return ret.ReturnCode;
}
Exemple #15
0
static int pbrpc_process_response(rdsServer* server, FDSAPI_MSG_PACKET* msg)
{
	pbRPCContext* context = server->rpc;
	pbRPCTransaction* ta = ListDictionary_GetItemValue(context->transactions, (void*)((UINT_PTR)msg->callId));

	if (!ta)
	{
		fprintf(stderr,"unsoliciated response - ignoring (tag %d)\n", msg->callId);
		return 1;
	}

	ListDictionary_Remove(context->transactions, (void*)((UINT_PTR)msg->callId));

	if (ta->responseCallback)
		ta->responseCallback(msg->status, msg, ta->callbackArg);

	if (ta->freeAfterResponse)
		free(ta);

	return 0;
}
Exemple #16
0
static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) {
	int index;
	int keyCount;
	ULONG_PTR* pKeys;
	SCARDCONTEXT hContext;
	SMARTCARD_CONTEXT* pContext;

	/**
	 * On protocol termination, the following actions are performed:
	 * For each context in rgSCardContextList, SCardCancel is called causing all SCardGetStatusChange calls to be processed.
	 * After that, SCardReleaseContext is called on each context and the context MUST be removed from rgSCardContextList.
	 */

	/**
	 * Call SCardCancel on existing contexts, unblocking all outstanding SCardGetStatusChange calls.
	 */

	if (ListDictionary_Count(smartcard->rgSCardContextList) > 0)
	{
		pKeys = NULL;
		keyCount = ListDictionary_GetKeys(smartcard->rgSCardContextList, &pKeys);

		for (index = 0; index < keyCount; index++)
		{
			pContext = (SMARTCARD_CONTEXT*) ListDictionary_GetItemValue(smartcard->rgSCardContextList, (void*) pKeys[index]);

			if (!pContext)
				continue;

			hContext = pContext->hContext;

			if (SCardIsValidContext(hContext) == SCARD_S_SUCCESS)
			{
				SCardCancel(hContext);
			}
		}

		free(pKeys);
	}

	/**
	 * Call SCardReleaseContext on remaining contexts and remove them from rgSCardContextList.
	 */

	if (ListDictionary_Count(smartcard->rgSCardContextList) > 0)
	{
		pKeys = NULL;
		keyCount = ListDictionary_GetKeys(smartcard->rgSCardContextList, &pKeys);

		for (index = 0; index < keyCount; index++)
		{
			pContext = (SMARTCARD_CONTEXT*) ListDictionary_Remove(smartcard->rgSCardContextList, (void*) pKeys[index]);

			if (!pContext)
				continue;

			hContext = pContext->hContext;

			if (SCardIsValidContext(hContext) == SCARD_S_SUCCESS)
			{
				SCardReleaseContext(hContext);

				if (MessageQueue_PostQuit(pContext->IrpQueue, 0) && (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED))
					WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", GetLastError());

				CloseHandle(pContext->thread);
				MessageQueue_Free(pContext->IrpQueue);	
				free(pContext);
			}
		}

		free(pKeys);
	}
}
Exemple #17
0
static void smartcard_init(DEVICE* device)
{
	int index;
	int keyCount;
	ULONG_PTR* pKeys;
	SCARDCONTEXT hContext;
	SMARTCARD_CONTEXT* pContext;
	SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) device;

	/**
	 * On protocol termination, the following actions are performed:
	 * For each context in rgSCardContextList, SCardCancel is called causing all outstanding messages to be processed.
	 * After there are no more outstanding messages, SCardReleaseContext is called on each context and the context MUST
	 * be removed from rgSCardContextList.
	 */

	/**
	 * Call SCardCancel on existing contexts, unblocking all outstanding IRPs.
	 */

	if (ListDictionary_Count(smartcard->rgSCardContextList) > 0)
	{
		pKeys = NULL;
		keyCount = ListDictionary_GetKeys(smartcard->rgSCardContextList, &pKeys);

		for (index = 0; index < keyCount; index++)
		{
			pContext = (SMARTCARD_CONTEXT*) ListDictionary_GetItemValue(smartcard->rgSCardContextList, (void*) pKeys[index]);

			if (!pContext)
				continue;

			hContext = pContext->hContext;

			if (SCardIsValidContext(hContext))
			{
				SCardCancel(hContext);
			}
		}

		free(pKeys);
	}

	/**
	 * Call SCardReleaseContext on remaining contexts and remove them from rgSCardContextList.
	 */

	if (ListDictionary_Count(smartcard->rgSCardContextList) > 0)
	{
		pKeys = NULL;
		keyCount = ListDictionary_GetKeys(smartcard->rgSCardContextList, &pKeys);

		for (index = 0; index < keyCount; index++)
		{
			pContext = (SMARTCARD_CONTEXT*) ListDictionary_Remove(smartcard->rgSCardContextList, (void*) pKeys[index]);

			if (!pContext)
				continue;

			hContext = pContext->hContext;

			if (SCardIsValidContext(hContext))
			{
				SCardReleaseContext(hContext);
			}
		}

		free(pKeys);
	}
}
Exemple #18
0
int pbrpc_call_method(rdsServer* server, UINT32 type, pbRPCPayload* request, pbRPCPayload** response)
{
	UINT32 tag;
	DWORD wait_ret;
	pbRPCTransaction ta;
	UINT32 ret = PBRPC_FAILED;
	FDSAPI_MSG_PACKET* msg;
	pbRPCContext* context = server->rpc;
	struct pbrpc_local_call_context local_context;

	if (!context->isConnected)
		return PBRCP_TRANSPORT_ERROR;

	tag = pbrpc_getTag(context);

	msg = pbrpc_message_new();

	msg->callId = tag;
	msg->status = FDSAPI_STATUS_SUCCESS;
	msg->buffer = request->buffer;
	msg->length = request->length;
	msg->msgType = FDSAPI_REQUEST_ID(type);

	ZeroMemory(&local_context, sizeof(local_context));
	local_context.event = CreateEvent(NULL, TRUE, FALSE, NULL);
	local_context.status = PBRCP_CALL_TIMEOUT;

	ta.responseCallback = pbrpc_response_local_cb;
	ta.callbackArg = &local_context;
	ta.freeAfterResponse = FALSE;

	ListDictionary_Add(context->transactions, (void*)((UINT_PTR)(msg->callId)), &ta);
	Queue_Enqueue(context->writeQueue, msg);

	wait_ret = WaitForSingleObject(local_context.event, 10000);

	if (wait_ret != WAIT_OBJECT_0)
	{
		if (!ListDictionary_Remove(context->transactions, (void*)((UINT_PTR)(tag))))
		{
			// special case - timeout occurred but request is already processing, see comment above
			WaitForSingleObject(local_context.event, INFINITE);
		}
		else
		{
			ret = PBRCP_CALL_TIMEOUT;
		}
	}

	CloseHandle(local_context.event);
	msg = local_context.response;

	if (!msg)
	{
		if (local_context.status)
			ret = local_context.status;
		else
			ret = PBRPC_FAILED;
	}
	else
	{
		*response = pbrpc_fill_payload(msg);
		ret = msg->status;
		pbrpc_message_free(msg, FALSE);
	}

	return ret;
}
Exemple #19
0
void remdesk_remove_open_handle_data(DWORD openHandle)
{
	void* pOpenHandle = (void*) (size_t) openHandle;
	ListDictionary_Remove(g_OpenHandles, pOpenHandle);
}
Exemple #20
0
void remdesk_remove_init_handle_data(void* pInitHandle)
{
	ListDictionary_Remove(g_InitHandles, pInitHandle);
}
Exemple #21
0
void svc_plugin_remove_init_handle_data(void* pInitHandle)
{
	ListDictionary_Remove(g_InitHandles, pInitHandle);
}
Exemple #22
0
void cliprdr_remove_init_handle_data(void* pInitHandle)
{
	ListDictionary_Remove(g_InitHandles, pInitHandle);
}
Exemple #23
0
static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp)
{
	IRP_THREAD_DATA* data = NULL;
	HANDLE irpThread;
	HANDLE previousIrpThread;
	uintptr_t key;
	/* for a test/debug purpose, uncomment the code below to get a
	 * single thread for all IRPs. NB: two IRPs could not be
	 * processed at the same time, typically two concurent
	 * Read/Write operations could block each other. */
	/* serial_process_irp(serial, irp); */
	/* irp->Complete(irp); */
	/* return; */
	/* NOTE: for good or bad, this implementation relies on the
	 * server to avoid a flooding of requests. see also _purge().
	 */
	EnterCriticalSection(&serial->TerminatingIrpThreadsLock);

	while (serial->IrpThreadToBeTerminatedCount > 0)
	{
		/* Cleaning up termitating and pending irp
		 * threads. See also: irp_thread_func() */
		HANDLE irpThread;
		ULONG_PTR* ids;
		int i, nbIds;
		nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids);

		for (i = 0; i < nbIds; i++)
		{
			/* Checking if ids[i] is terminating or pending */
			DWORD waitResult;
			ULONG_PTR id = ids[i];
			irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id);
			/* FIXME: not quite sure a zero timeout is a good thing to check whether a thread is stil alived or not */
			waitResult = WaitForSingleObject(irpThread, 0);

			if (waitResult == WAIT_OBJECT_0)
			{
				/* terminating thread */
				/* WLog_Print(serial->log, WLOG_DEBUG, "IRP thread with CompletionId=%"PRIuz" naturally died", id); */
				CloseHandle(irpThread);
				ListDictionary_Remove(serial->IrpThreads, (void*)id);
				serial->IrpThreadToBeTerminatedCount--;
			}
			else if (waitResult != WAIT_TIMEOUT)
			{
				/* unexpected thread state */
				WLog_Print(serial->log, WLOG_WARN,
				           "WaitForSingleObject, got an unexpected result=0x%"PRIX32"\n", waitResult);
				assert(FALSE);
			}

			/* pending thread (but not yet terminating thread) if waitResult == WAIT_TIMEOUT */
		}

		if (serial->IrpThreadToBeTerminatedCount > 0)
		{
			WLog_Print(serial->log, WLOG_DEBUG, "%"PRIu32" IRP thread(s) not yet terminated",
			           serial->IrpThreadToBeTerminatedCount);
			Sleep(1); /* 1 ms */
		}
	}

	LeaveCriticalSection(&serial->TerminatingIrpThreadsLock);
	/* NB: At this point and thanks to the synchronization we're
	 * sure that the incoming IRP uses well a recycled
	 * CompletionId or the server sent again an IRP already posted
	 * which didn't get yet a response (this later server behavior
	 * at least observed with IOCTL_SERIAL_WAIT_ON_MASK and
	 * mstsc.exe).
	 *
	 * FIXME: behavior documented somewhere? behavior not yet
	 * observed with FreeRDP).
	 */
	key = irp->CompletionId;
	previousIrpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)key);

	if (previousIrpThread)
	{
		/* Thread still alived <=> Request still pending */
		WLog_Print(serial->log, WLOG_DEBUG,
		           "IRP recall: IRP with the CompletionId=%"PRIu32" not yet completed!",
		           irp->CompletionId);
		assert(FALSE); /* unimplemented */
		/* TODO: asserts that previousIrpThread handles well
		 * the same request by checking more details. Need an
		 * access to the IRP object used by previousIrpThread
		 */
		/* TODO: taking over the pending IRP or sending a kind
		 * of wake up signal to accelerate the pending
		 * request
		 *
		 * To be considered:
		 *   if (IoControlCode == IOCTL_SERIAL_WAIT_ON_MASK) {
		 *       pComm->PendingEvents |= SERIAL_EV_FREERDP_*;
		 *   }
		 */
		irp->Discard(irp);
		return;
	}

	if (ListDictionary_Count(serial->IrpThreads) >= MAX_IRP_THREADS)
	{
		WLog_Print(serial->log, WLOG_WARN,
		           "Number of IRP threads threshold reached: %d, keep on anyway",
		           ListDictionary_Count(serial->IrpThreads));
		assert(FALSE); /* unimplemented */
		/* TODO: MAX_IRP_THREADS has been thought to avoid a
		 * flooding of pending requests. Use
		 * WaitForMultipleObjects() when available in winpr
		 * for threads.
		 */
	}

	/* error_handle to be used ... */
	data = (IRP_THREAD_DATA*)calloc(1, sizeof(IRP_THREAD_DATA));

	if (data == NULL)
	{
		WLog_Print(serial->log, WLOG_WARN, "Could not allocate a new IRP_THREAD_DATA.");
		goto error_handle;
	}

	data->serial = serial;
	data->irp = irp;
	/* data freed by irp_thread_func */
	irpThread = CreateThread(NULL,
	                         0,
	                         (LPTHREAD_START_ROUTINE)irp_thread_func,
	                         (void*)data,
	                         0,
	                         NULL);

	if (irpThread == INVALID_HANDLE_VALUE)
	{
		WLog_Print(serial->log, WLOG_WARN, "Could not allocate a new IRP thread.");
		goto error_handle;
	}

	key = irp->CompletionId;

	if (!ListDictionary_Add(serial->IrpThreads, (void*)key, irpThread))
	{
		WLog_ERR(TAG, "ListDictionary_Add failed!");
		goto error_handle;
	}

	return;
error_handle:
	irp->IoStatus = STATUS_NO_MEMORY;
	irp->Complete(irp);
	free(data);
}
int TestListDictionary(int argc, char* argv[])
{
	int count;
	char* value;
	wListDictionary* list;

	list = ListDictionary_New(FALSE);

	ListDictionary_Add(list, key1, val1);
	ListDictionary_Add(list, key2, val2);
	ListDictionary_Add(list, key3, val3);

	count = ListDictionary_Count(list);

	if (count != 3)
	{
		printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 3, count);
		return -1;
	}

	ListDictionary_Remove(list, key2);

	count = ListDictionary_Count(list);

	if (count != 2)
	{
		printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 2, count);
		return -1;
	}

	ListDictionary_Remove(list, key3);

	count = ListDictionary_Count(list);

	if (count != 1)
	{
		printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 1, count);
		return -1;
	}

	ListDictionary_Remove(list, key1);

	count = ListDictionary_Count(list);

	if (count != 0)
	{
		printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 0, count);
		return -1;
	}

	ListDictionary_Add(list, key1, val1);
	ListDictionary_Add(list, key2, val2);
	ListDictionary_Add(list, key3, val3);

	count = ListDictionary_Count(list);

	if (count != 3)
	{
		printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 3, count);
		return -1;
	}

	value = (char*) ListDictionary_GetItemValue(list, key1);

	if (strcmp(value, val1) != 0)
	{
		printf("ListDictionary_GetItemValue: Expected : %d, Actual: %d\n", val1, value);
		return -1;
	}

	value = (char*) ListDictionary_GetItemValue(list, key2);

	if (strcmp(value, val2) != 0)
	{
		printf("ListDictionary_GetItemValue: Expected : %d, Actual: %d\n", val2, value);
		return -1;
	}

	value = (char*) ListDictionary_GetItemValue(list, key3);

	if (strcmp(value, val3) != 0)
	{
		printf("ListDictionary_GetItemValue: Expected : %d, Actual: %d\n", val3, value);
		return -1;
	}

	ListDictionary_SetItemValue(list, key2, "apple");

	value = (char*) ListDictionary_GetItemValue(list, key2);

	if (strcmp(value, "apple") != 0)
	{
		printf("ListDictionary_GetItemValue: Expected : %d, Actual: %d\n", "apple", value);
		return -1;
	}

	if (!ListDictionary_Contains(list, key2))
	{
		printf("ListDictionary_Contains: Expected : %d, Actual: %d\n", TRUE, FALSE);
		return -1;
	}

	ListDictionary_Clear(list);

	count = ListDictionary_Count(list);

	if (count != 0)
	{
		printf("ListDictionary_Count: Expected : %d, Actual: %d\n", 0, count);
		return -1;
	}

	ListDictionary_Free(list);

	return 0;
}