#include "SdpTrace.h"\r
#include "sdpLock.h"\r
#include "RefCount.h"\r
+#include "SdpBufferPool.h"\r
#include "sdpdriver.h"\r
#include "SdpShared.h"\r
#include "SdpUserFile.h"\r
-#include "SdpBufferPool.h"\r
#include "SdpRecvPool.h"\r
#include "SdpConnectionList.h"\r
#include "SdpSocket.h"\r
SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("called pDriverObject = 0x%x\n", pDriverObject ));\r
ib_api_status_t ib_status;\r
\r
+ g_pSdpDriver->WaitForAllThreadsToDie();\r
+\r
\r
ib_status = ib_close_al(g_pSdpDriver->m_al_handle);\r
g_pSdpDriver->m_al_handle = NULL;\r
IN PDRIVER_OBJECT pDriverObject,\r
IN PUNICODE_STRING pRegistryPath )\r
{\r
- NTSTATUS rc;\r
+ NTSTATUS rc = STATUS_SUCCESS;\r
ib_api_status_t ib_status;\r
PDEVICE_OBJECT pDevObj;\r
SdpDriver *pSdpDriver;\r
}\r
DeviceCreated = true;\r
\r
- pSdpDriver = (SdpDriver *) pDevObj->DeviceExtension;\r
+ pSdpDriver = new (pDevObj->DeviceExtension) SdpDriver;\r
rc = pSdpDriver->Init(pDevObj);\r
\r
if (!NT_SUCCESS(rc)) {\r
goto Cleanup; \\r
}\r
\r
-NTSTATUS SdpDriver::Init(PDEVICE_OBJECT pDevObj) \r
+NTSTATUS \r
+SdpDriver::Init(PDEVICE_OBJECT pDevObj) \r
{\r
NTSTATUS rc = STATUS_SUCCESS;\r
m_pDevObj = pDevObj;\r
SDP_PRINT(SDP_ERR, SDP_DRIVER, ("m_pSdpArp->Init failed rc = 0x%x\n", rc )); \r
goto Cleanup;\r
}\r
-Cleanup: \r
+\r
+ ExInitializeFastMutex(&m_ThreadsMutex);\r
+ \r
+Cleanup:\r
+ if (!NT_SUCCESS(rc)) {\r
+ if (m_pSdpArp) {\r
+ delete m_pSdpArp;\r
+ }\r
+ }\r
return rc;\r
}\r
\r
\r
-NTSTATUS SdpDriver::DispatchDeviceIoControl(\r
+NTSTATUS \r
+SdpDriver::DispatchDeviceIoControl(\r
IN PFILE_OBJECT pDeviceObject,\r
IN PIRP pIrp,\r
IN PIO_STACK_LOCATION pIrpSp,\r
return rc;\r
}\r
\r
+VOID \r
+SdpDriver::AddThread(ThreadHandle *pThreadHandle)\r
+{\r
+ SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("this = 0x%x\n", this ));\r
+ // Check if there is any next thread that can be removed from the queue\r
+ LARGE_INTEGER WaitTime;\r
+ WaitTime.QuadPart = 0; // Don't wait for them to die\r
+\r
+ ExAcquireFastMutex(&m_ThreadsMutex);\r
+\r
+ WaitForThreadsToDie(&WaitTime);\r
+\r
+ // Add me to the list of threads that should be removed\r
+ m_ShutDownThreads.InsertTailList(&pThreadHandle->m_List);\r
+ ExReleaseFastMutex(&m_ThreadsMutex);\r
+\r
+}\r
+\r
+VOID \r
+SdpDriver::WaitForAllThreadsToDie()\r
+{\r
+ SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("this = 0x%x\n", this ));\r
+\r
+ ExAcquireFastMutex(&m_ThreadsMutex);\r
+ // Timeout of null will cause a wait forever\r
+ WaitForThreadsToDie(NULL);\r
+ ExReleaseFastMutex(&m_ThreadsMutex);\r
+}\r
+\r
+\r
+// This function has to be called with the mutex held\r
+VOID \r
+SdpDriver::WaitForThreadsToDie(LARGE_INTEGER *pWaitTime)\r
+{\r
+ SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("this = 0x%x\n", this ));\r
+ // Check if there is any next thread that can be removed from the queue\r
+ NTSTATUS rc = STATUS_SUCCESS;\r
+\r
+ LIST_ENTRY *pNextItem;\r
+ ThreadHandle *pNextThreadHandle;\r
+ while (m_ShutDownThreads.Size() > 0) {\r
+ pNextItem = m_ShutDownThreads.Head();\r
+ pNextThreadHandle = CONTAINING_RECORD(pNextItem, ThreadHandle, m_List);\r
+\r
+ rc = MyKeWaitForSingleObject(\r
+ pNextThreadHandle->ThreadObject, \r
+ Executive,\r
+ KernelMode,\r
+ FALSE,\r
+ pWaitTime\r
+ );\r
+ ASSERT((rc == STATUS_SUCCESS) ||\r
+ (rc == STATUS_TIMEOUT));\r
+\r
+ if (rc == STATUS_TIMEOUT) {\r
+ // Nothing that we should do, the thread is not ready yet\r
+ SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("this = 0x%x Former thread is not dead yet\n", this ));\r
+ break;\r
+ }\r
+ // SUCESS means that the thread is dead, we can remove it\r
+ // from the list\r
+ SDP_PRINT(SDP_TRACE, SDP_DRIVER, ("this = 0x%x Former thread is already dead\n", this ));\r
+\r
+ m_ShutDownThreads.RemoveHeadList();\r
+ ObDereferenceObject(pNextThreadHandle->ThreadObject);\r
+ delete pNextThreadHandle;\r
+ \r
+ // We now continue and try to remove the next object\r
+\r
+ }\r
+\r
+}\r
+\r
\r
#ifndef H_SDP_DRIVER_H\r
#define H_SDP_DRIVER_H \r
\r
+// This struct is being used to hold an object that we can wait on\r
+// for threads to die.\r
+\r
+struct ThreadHandle {\r
+ // As this object has a simple life cycle I don't use refferance counting\r
+ // for it. This might have to change.\r
+ PVOID ThreadObject;\r
+ LIST_ENTRY m_List;\r
+};\r
+\r
\r
class SdpDriver {\r
public:\r
IN ULONG IoControlCode,\r
OUT ULONG &OutputDataSize\r
);\r
- \r
- \r
+\r
+ // The following functions are being used so that the driver\r
+ // will wait for all the created threads to end\r
+ VOID AddThread(ThreadHandle *pThreadHandle);\r
+\r
+ VOID WaitForAllThreadsToDie(); \r
\r
public:\r
ib_al_handle_t m_al_handle ;\r
\r
private:\r
\r
+ VOID WaitForThreadsToDie(LARGE_INTEGER *pWWaitTime);\r
+\r
+\r
PDEVICE_OBJECT m_pDevObj;\r
\r
+ LinkedList m_ShutDownThreads;\r
+\r
+ FAST_MUTEX m_ThreadsMutex;\r
\r
};\r
\r
ExFreePoolWithTag(p, GLOBAL_ALLOCATION_TAG);\r
}\r
\r
+void* __cdecl operator new(size_t n, void *addr ) throw() {\r
+ return addr;\r
+}\r
+\r
+\r
\r
NTSTATUS Sleep(ULONG HandredNanos);\r
\r
+void* __cdecl operator new(size_t n, void *addr ) throw();\r
\r
/* Convert an IBAL error to a Winsock error. */\r
int IbalToWsaError(const ib_api_status_t ib_status );\r
static void AL_API\r
cm_dreq_callback(IN ib_cm_dreq_rec_t *p_cm_dreq_rec )\r
{\r
- SDP_PRINT(SDP_TRACE, SDP_SOCKET, ("dispatch level = %d\n", KeGetCurrentIrql()));\r
SdpSocket *pSocket = (SdpSocket *) p_cm_dreq_rec->qp_context;\r
pSocket->CmDreqCallback(p_cm_dreq_rec);\r
-\r
}\r
\r
static void AL_API\r
\r
m_ConnectionList.Init(this);\r
\r
+ // We now allocate the needed structure for the close socket, so that \r
+ // we won't be in trouble after the thread was created\r
+ m_pCloseSocketThread = new ThreadHandle;\r
+ if (m_pCloseSocketThread == NULL) {\r
+ SDP_PRINT(SDP_ERR, SDP_SOCKET, ("Failed to allocate new SocketThread this = 0x%p \n",this));\r
+ rc = STATUS_NO_MEMORY;\r
+ goto Cleanup;\r
+ }\r
+ \r
+Cleanup:\r
return rc;\r
}\r
\r
} \r
\r
// I want to copy this data before releasing the lock\r
- ULONG IP = m_DstIp;\r
- USHORT Port = m_DstPort; \r
+ ULONG IP = pNewSocket->m_DstIp;\r
+ USHORT Port = pNewSocket->m_DstPort; \r
\r
ASSERT(Locked == true);\r
rc = m_Lock.Unlock();\r
)\r
{\r
NTSTATUS rc = STATUS_SUCCESS;\r
- SDP_PRINT(SDP_TRACE, SDP_SOCKET, ("this = 0x%p\n",this));\r
+ SDP_PRINT(SDP_TRACE, SDP_SOCKET, ("this = 0x%p state = %s \n",this, SS2String(m_state)));\r
OBJECT_ATTRIBUTES attr;\r
\r
if (!m_Lock.Lock()) {\r
m_Lock.Unlock(); // Error ignored as this is already an error pass\r
goto Cleanup;\r
}\r
- }\r
\r
- // We will now create a thread that will be resposible for the\r
- // destruction of this socket\r
- AddRef();\r
+ // We will now create a thread that will be resposible for the\r
+ // destruction of this socket\r
+ AddRef();\r
\r
\r
- /* Create a new thread, storing both the handle and thread id. */\r
- InitializeObjectAttributes( &attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );\r
- \r
- HANDLE ThreadHandle;\r
- rc = PsCreateSystemThread(\r
- &ThreadHandle, \r
- THREAD_ALL_ACCESS,\r
- &attr,\r
- NULL,\r
- NULL,\r
- ::CloseSocketThread,\r
- this\r
- );\r
+ /* Create a new thread, storing both the handle and thread id. */\r
+ InitializeObjectAttributes( &attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );\r
+ \r
+ HANDLE ThreadHandle;\r
+ rc = PsCreateSystemThread(\r
+ &ThreadHandle, \r
+ THREAD_ALL_ACCESS,\r
+ &attr,\r
+ NULL,\r
+ NULL,\r
+ ::CloseSocketThread,\r
+ this\r
+ );\r
+\r
+ if (!NT_SUCCESS(rc)) {\r
+ SDP_PRINT(SDP_ERR, SDP_SOCKET, ("PsCreateSystemThread failed rc = 0x%x\n", rc ));\r
+ m_Lock.Unlock(); // Error ignored as this is already an error pass\r
+ // The thread wasn't created so we should remove the refferance\r
+ Release(); \r
+ goto Cleanup;\r
+ }\r
+\r
+ ASSERT(m_pCloseSocketThread != NULL);\r
+ // Convert the thread into a handle\r
+ rc = ObReferenceObjectByHandle(\r
+ ThreadHandle,\r
+ THREAD_ALL_ACCESS,\r
+ NULL,\r
+ KernelMode,\r
+ &m_pCloseSocketThread->ThreadObject,\r
+ NULL\r
+ );\r
+ ASSERT(rc == STATUS_SUCCESS); // According to MSDN, if I set the params\r
+ // correctly I shouldn't get an error\r
+ \r
+ rc = ZwClose(ThreadHandle);\r
+ ASSERT(NT_SUCCESS(rc)); // Should always succeed\r
+\r
+ g_pSdpDriver->AddThread(m_pCloseSocketThread);\r
+ m_pCloseSocketThread = NULL; // Will be delated when the callback thread is deleted\r
\r
- if (!NT_SUCCESS(rc)) {\r
- SDP_PRINT(SDP_ERR, SDP_SOCKET, ("PsCreateSystemThread failed rc = 0x%x\n", rc ));\r
- m_Lock.Unlock(); // Error ignored as this is already an error pass\r
- // The thread wasn't created so we should remove the refferance\r
- Release(); \r
- goto Cleanup;\r
}\r
\r
- // BUGBUG: Replace this with a mechanism that will allow\r
- // to close the thered when the driver goes down\r
- rc = ZwClose(ThreadHandle);\r
- ASSERT(NT_SUCCESS(rc)); // Should succeed\r
+\r
\r
rc = m_Lock.Unlock();\r
if (!NT_SUCCESS(rc)) {\r
VOID \r
SdpSocket::CmDreqCallback(IN ib_cm_dreq_rec_t *p_cm_dreq_rec)\r
{\r
- SDP_PRINT(SDP_TRACE, SDP_SOCKET, ("this = 0x%p\n", this));\r
+ SDP_PRINT(SDP_TRACE, SDP_SOCKET, ("this = 0x%p, dispatch level = %d\n", this, KeGetCurrentIrql()));\r
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);\r
NTSTATUS rc = STATUS_SUCCESS;\r
ib_cm_drep_t cm_drep;\r
goto ErrorLocked;\r
}\r
\r
- // last step is to change our state\r
+ // last step is to change our state (this will affect close socket for example)\r
m_state = SS_CONNECTED_DREP_SENT;\r
\r
// We should close the connection know ??????????/\r
m_pListeningSocket->Release();\r
m_pListeningSocket = NULL;\r
}\r
+\r
+ if (m_pCloseSocketThread != NULL) {\r
+ delete m_pCloseSocketThread;\r
+ m_pCloseSocketThread = NULL;\r
+ }\r
\r
\r
// Now that all ibal operations have finished we can free the memory\r
bool m_ShutdownCalled;\r
bool m_DisconnectConnectionRecieved;\r
\r
+ ThreadHandle* m_pCloseSocketThread;\r
+\r
\r
\r
VOID SignalShutdown();\r
* check the way that errors are reported to the user mode. It seems that returning an error\r
in rc means that the output buffer won't pass out.\r
\r
-* make sure that the "terminator thread" is being killed before we exit.\r
-\r
* Check why sometimes the QP and so are not valid when you come to kill them\r