libwinpr-nt: implement NtCurrentTeb()

This commit is contained in:
Marc-André Moreau 2013-08-22 10:18:38 -04:00
parent c878200e00
commit 68ec10a9d9
15 changed files with 550 additions and 21 deletions

View File

@ -498,7 +498,7 @@ BOOL tf_peer_post_connect(freerdp_peer* client)
{
if (strncmp(client->settings->ChannelDefArray[i].Name, "rdpdbg", 6) == 0)
{
context->debug_channel = WTSVirtualChannelOpenEx(context->vcm, "rdpdbg", 0);
context->debug_channel = WTSVirtualChannelManagerOpenEx(context->vcm, "rdpdbg", 0);
if (context->debug_channel != NULL)
{
@ -580,7 +580,7 @@ void tf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
{
if (context->debug_channel)
{
WTSVirtualChannelWrite(context->debug_channel, (BYTE*) "test2", 5, NULL);
WTSVirtualChannelWrite(context->debug_channel, (PCHAR) "test2", 5, NULL);
}
}
else if ((flags & 0x4000) && code == 0x2D) /* 'x' key */

77
winpr/include/winpr/nt.h Normal file
View File

@ -0,0 +1,77 @@
/**
* WinPR: Windows Portable Runtime
* Windows Native System Services
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_NT_H
#define WINPR_NT_H
#include <winpr/winpr.h>
#include <winpr/wtypes.h>
#ifndef _WIN32
typedef struct _PEB PEB;
typedef struct _PEB* PPEB;
typedef struct _TEB TEB;
typedef struct _TEB* PTEB;
/**
* Process Environment Block
*/
struct _THREAD_BLOCK_ID
{
DWORD ThreadId;
TEB* ThreadEnvironmentBlock;
};
typedef struct _THREAD_BLOCK_ID THREAD_BLOCK_ID;
struct _PEB
{
DWORD ThreadCount;
DWORD ThreadArraySize;
THREAD_BLOCK_ID* Threads;
};
/*
* Thread Environment Block
*/
struct _TEB
{
PEB* ProcessEnvironmentBlock;
DWORD LastErrorValue;
PVOID TlsSlots[64];
};
#ifdef __cplusplus
extern "C" {
#endif
WINPR_API PTEB NtCurrentTeb(void);
#ifdef __cplusplus
}
#endif
#endif
#endif /* WINPR_NT_H */

View File

@ -31,10 +31,20 @@ add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
MODULE winpr
MODULES winpr-nt)
if(MONOLITHIC_BUILD)
else()
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR")
if(BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@ -23,25 +23,12 @@
#include <winpr/error.h>
/**
* api-ms-win-core-errorhandling-l1-1-1.dll:
*
* GetErrorMode
* SetErrorMode
* GetLastError
* SetLastError
* RestoreLastError
* RaiseException
* UnhandledExceptionFilter
* SetUnhandledExceptionFilter
* AddVectoredExceptionHandler
* RemoveVectoredExceptionHandler
* AddVectoredContinueHandler
* RemoveVectoredContinueHandler
*/
#ifndef _WIN32
#include <stdio.h>
#include <winpr/nt.h>
UINT GetErrorMode(void)
{
return 0;
@ -54,12 +41,12 @@ UINT SetErrorMode(UINT uMode)
DWORD GetLastError(VOID)
{
return 0;
return NtCurrentTeb()->LastErrorValue;
}
VOID SetLastError(DWORD dwErrCode)
{
NtCurrentTeb()->LastErrorValue = dwErrCode;
}
VOID RestoreLastError(DWORD dwErrCode)

3
winpr/libwinpr/error/test/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
TestError
TestError.c

View File

@ -0,0 +1,31 @@
set(MODULE_NAME "TestError")
set(MODULE_PREFIX "TEST_ERROR")
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS
TestErrorSetLastError.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${MODULE_PREFIX}_DRIVER}
${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-crt winpr-synch winpr-thread winpr-error)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@ -0,0 +1,89 @@
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/error.h>
static int status = 0;
static DWORD errors[4] =
{
ERROR_INVALID_DATA,
ERROR_BROKEN_PIPE,
ERROR_INVALID_NAME,
ERROR_BAD_ARGUMENTS
};
static void* test_error_thread(void* arg)
{
int id;
DWORD error;
id = (int) (size_t) arg;
error = errors[id];
SetLastError(error);
Sleep(10);
error = GetLastError();
if (error != errors[id])
{
printf("GetLastError() failure (thread %d): Expected: 0x%04X, Actual: 0x%04X\n",
id, errors[id], error);
if (!status)
status = -1;
return NULL;
}
return NULL;
}
int TestErrorSetLastError(int argc, char* argv[])
{
DWORD error;
HANDLE threads[4];
SetLastError(ERROR_ACCESS_DENIED);
error = GetLastError();
if (error != ERROR_ACCESS_DENIED)
{
printf("GetLastError() failure: Expected: 0x%04X, Actual: 0x%04X\n",
ERROR_ACCESS_DENIED, error);
return -1;
}
threads[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) test_error_thread, (void*) (size_t) 0, 0, NULL);
threads[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) test_error_thread, (void*) (size_t) 1, 0, NULL);
threads[2] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) test_error_thread, (void*) (size_t) 2, 0, NULL);
threads[3] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) test_error_thread, (void*) (size_t) 3, 0, NULL);
WaitForSingleObject(threads[0], INFINITE);
WaitForSingleObject(threads[1], INFINITE);
WaitForSingleObject(threads[2], INFINITE);
WaitForSingleObject(threads[3], INFINITE);
CloseHandle(threads[0]);
CloseHandle(threads[1]);
CloseHandle(threads[2]);
CloseHandle(threads[3]);
error = GetLastError();
if (error != ERROR_ACCESS_DENIED)
{
printf("GetLastError() failure: Expected: 0x%04X, Actual: 0x%04X\n",
ERROR_ACCESS_DENIED, error);
return -1;
}
return status;
}

View File

@ -0,0 +1,53 @@
# WinPR: Windows Portable Runtime
# libwinpr-nt cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(MODULE_NAME "winpr-nt")
set(MODULE_PREFIX "WINPR_NT")
set(${MODULE_PREFIX}_SRCS
nt.c)
if(MSVC AND (NOT MONOLITHIC_BUILD))
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def)
endif()
add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
MONOLITHIC ${MONOLITHIC_BUILD}
SOURCES ${${MODULE_PREFIX}_SRCS})
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib")
set(${MODULE_PREFIX}_LIBS
${CMAKE_THREAD_LIBS_INIT}
${CMAKE_DL_LIBS})
if(${CMAKE_SYSTEM_NAME} MATCHES SunOS)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rt)
endif()
if(MONOLITHIC_BUILD)
set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
else()
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR")
if(BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@ -0,0 +1,8 @@
set(MINWIN_LAYER "0")
set(MINWIN_GROUP "none")
set(MINWIN_MAJOR_VERSION "0")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "nt")
set(MINWIN_LONG_NAME "Windows Native System Services")
set(MODULE_LIBRARY_NAME "${MINWIN_SHORT_NAME}")

View File

@ -0,0 +1,3 @@
LIBRARY "libwinpr-nt"
EXPORTS

205
winpr/libwinpr/nt/nt.c Normal file
View File

@ -0,0 +1,205 @@
/**
* WinPR: Windows Portable Runtime
* Windows Native System Services
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/nt.h>
/**
* NtXxx Routines:
* http://msdn.microsoft.com/en-us/library/windows/hardware/ff557720/
*/
#ifndef _WIN32
#include <pthread.h>
#include <winpr/crt.h>
/**
* The current implementation of NtCurrentTeb() is not the most efficient
* but it's a starting point. Beware of potential performance bottlenecks
* caused by multithreaded usage of SetLastError/GetLastError.
*/
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static PPEB g_ProcessEnvironmentBlock = NULL;
static void NtThreadEnvironmentBlockFree(PTEB teb);
static void NtProcessEnvironmentBlockFree(PPEB peb);
static PTEB NtThreadEnvironmentBlockNew()
{
PTEB teb = NULL;
pthread_key_t key;
teb = (PTEB) malloc(sizeof(TEB));
if (teb)
{
ZeroMemory(teb, sizeof(TEB));
/**
* We are not really using the key, but it provides an automatic way
* of calling NtThreadEnvironmentBlockFree on thread termination for
* the current Thread Environment Block.
*/
pthread_key_create(&key, (void (*)(void*)) NtThreadEnvironmentBlockFree);
pthread_setspecific(key, (void*) teb);
}
return teb;
}
static void NtThreadEnvironmentBlockFree(PTEB teb)
{
DWORD index;
PPEB peb = NULL;
peb = teb->ProcessEnvironmentBlock;
pthread_mutex_lock(&mutex);
for (index = 0; index < peb->ThreadArraySize; index++)
{
if (peb->Threads[index].ThreadEnvironmentBlock == teb)
{
peb->Threads[index].ThreadId = 0;
peb->Threads[index].ThreadEnvironmentBlock = NULL;
peb->ThreadCount--;
break;
}
}
if (!peb->ThreadCount)
{
NtProcessEnvironmentBlockFree(peb);
}
pthread_mutex_unlock(&mutex);
free(teb);
}
static PPEB NtProcessEnvironmentBlockNew()
{
PPEB peb = NULL;
peb = (PPEB) malloc(sizeof(PEB));
if (peb)
{
ZeroMemory(peb, sizeof(PEB));
peb->ThreadCount = 0;
peb->ThreadArraySize = 64;
peb->Threads = (THREAD_BLOCK_ID*) malloc(sizeof(THREAD_BLOCK_ID) * peb->ThreadArraySize);
if (peb->Threads)
{
ZeroMemory(peb->Threads, sizeof(THREAD_BLOCK_ID) * peb->ThreadArraySize);
}
}
return peb;
}
static void NtProcessEnvironmentBlockFree(PPEB peb)
{
if (peb)
{
free(peb->Threads);
free(peb);
}
g_ProcessEnvironmentBlock = NULL;
}
PPEB NtCurrentPeb(void)
{
PPEB peb = NULL;
pthread_mutex_lock(&mutex);
if (!g_ProcessEnvironmentBlock)
g_ProcessEnvironmentBlock = NtProcessEnvironmentBlockNew();
peb = g_ProcessEnvironmentBlock;
pthread_mutex_unlock(&mutex);
return peb;
}
PTEB NtCurrentTeb(void)
{
DWORD index;
int freeIndex;
DWORD ThreadId;
PPEB peb = NULL;
PTEB teb = NULL;
peb = NtCurrentPeb();
ThreadId = (DWORD) pthread_self();
freeIndex = -1;
pthread_mutex_lock(&mutex);
for (index = 0; index < peb->ThreadArraySize; index++)
{
if (!peb->Threads[index].ThreadId)
{
if (freeIndex < 0)
freeIndex = (int) index;
}
if (peb->Threads[index].ThreadId == ThreadId)
{
teb = peb->Threads[index].ThreadEnvironmentBlock;
break;
}
}
if (!teb)
{
if (freeIndex >= 0)
{
teb = NtThreadEnvironmentBlockNew();
peb->Threads[freeIndex].ThreadEnvironmentBlock = teb;
peb->Threads[freeIndex].ThreadId = ThreadId;
peb->ThreadCount++;
teb->ProcessEnvironmentBlock = peb;
teb->LastErrorValue = 0;
}
}
pthread_mutex_unlock(&mutex);
return teb;
}
#endif

3
winpr/libwinpr/nt/test/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
TestNt
TestNt.c

View File

@ -0,0 +1,32 @@
set(MODULE_NAME "TestNt")
set(MODULE_PREFIX "TEST_NT")
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS
TestNtCreateFile.c
TestNtCurrentTeb.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${MODULE_PREFIX}_DRIVER}
${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-crt winpr-nt)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@ -0,0 +1,8 @@
#include <winpr/nt.h>
int TestNtCreateFile(int argc, char* argv[])
{
return 0;
}

View File

@ -0,0 +1,20 @@
#include <stdio.h>
#include <winpr/nt.h>
int TestNtCurrentTeb(int argc, char* argv[])
{
PTEB teb;
teb = NtCurrentTeb();
if (!teb)
{
printf("NtCurrentTeb() returned NULL\n");
return -1;
}
return 0;
}