Здравствуйте, Zoya_Pobeda, Вы писали:
Z_P>Здраствуйте, мальчики
Z_P>Есть драйвет виртуального ЛПТ-порта.Он получает данные от приложения — с этим все ОК!Добила!
Z_P>Нужно эти данные отпралять по сети...Вот здесь не все мне понятно. Как я понимаю, нужно создать транспорт.файл, файл соединения, выстатвит события, ассоциировать, сохранить Irp Accept-a, по событию конект, отдать этот Irp — работаем...
Z_P>Так вот вопрос: Нужно ли все это дело связанное с TDI, выносить в отдельный поток?
Вы довольно сумбурно изложили свои мысли, видимо сказалась радость победы на LPT

.Ваш драйвер будет сетевым сервером или клиентом? Если клиентом, то когда должно устанавливтаься соединение? Короче говоря, не совсем ясна архитектура. Поэтому и ответ будет таким же неясным. Большинство вызовов (кроме создания транспортных объектов ) могут проходить на DISPATCH_LEVEL и могут быть сделаны в контексте любого потока.
Здравствуйте, TarasCo, Вы писали:
TC>Вы довольно сумбурно изложили свои мысли, видимо сказалась радость победы на LPT
.Ваш драйвер будет сетевым сервером или клиентом? Если клиентом, то когда должно устанавливтаься соединение? Короче говоря, не совсем ясна архитектура. Поэтому и ответ будет таким же неясным. Большинство вызовов (кроме создания транспортных объектов ) могут проходить на DISPATCH_LEVEL и могут быть сделаны в контексте любого потока.
Может быть как сервером, так и клиентом, взависимости от настроек.Но в данном случае меня интересует серверная часть.
Архитектура такова: Девайс ЛПТ, при открытии должен(помимо каких то своих настроек), создавать поток, который будет работать с ТДИ. Все это дело у меня сейчас выглядит примерно так:
NTSTATUS ServerThreadStart(PLPT_DEVICE_EXTENSION Context)
{
NTSTATUS status = STATUS_SUCCESS;
PSERVERDATA pServer = NULL;
KeInitializeSemaphore(&Context->Tdi_KillEvent, 0, MAXLONG);
KeInitializeSemaphore(&Context->Tdi_TimeWait, 0, MAXLONG);
KeInitializeSemaphore(&Context->Tdi_Send, 0, MAXLONG);
KeInitializeSemaphore(&Context->Tdi_Recv, 0, MAXLONG);
pServer = ExAllocatePool(NonPagedPool, sizeof(SERVERDATA));
if( NULL == pServer )
{
return( STATUS_INSUFFICIENT_RESOURCES );
}
memset( pServer, 0, sizeof( SERVERDATA ) );
pServer->pDevExt = Context;
status = PsCreateSystemThread(
&pServer->hTestThread, // thread handle
0L, // desired access
NULL, // object attributes
NULL, // process handle
NULL, // client id
ServerWorkerThread, // start routine
(PVOID )pServer // start context
);
if( !NT_SUCCESS( status ) )
{
// goto errorServerWorkerThread;
}
return status;
}
VOID ServerWorkerThread(IN PVOID Context)
{
NTSTATUS status = STATUS_SUCCESS;
LARGE_INTEGER DelayTime;
PVOID pEvents[6];
KWAIT_BLOCK waitBlocks[6];
BOOLEAN bDeadThread = FALSE;
PIRP pIrp = NULL;
IO_STATUS_BLOCK IoStatus;
PSERVERDATA pServer = (PSERVERDATA)Context;
PLPT_DEVICE_EXTENSION pDevExt = (PLPT_DEVICE_EXTENSION)pServer->pDevExt;
pServer->pTDIClient = ExAllocatePool(NonPagedPool, sizeof( TDIClientExtension ));
if( NULL == pServer->pTDIClient )
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto errorTDIClient;
}
pServer->pTDIClient->hAddr = INVALID_HANDLE_VALUE;
pServer->pTDIClient->pAddrFileObj = NULL;
pServer->pTDIClient->pReqElemsArr = NULL;
pServer->pTDIClient->pBufferBase = NULL;
pServer->pTDIClient->pTDIClnConnArr = NULL;
InitIPAddress( &pServer->pTDIClient->LocalAddress,
INADDR_ANY,
ntohs(pDevExt->m_port));
status = TDIClnOpenTransAddr(
TCP_DEVICE_NAME_W,
pServer->pTDIClient,
&pServer->pTDIClient->hAddr,
&pServer->pTDIClient->pAddrFileObj
);
if( !NT_SUCCESS( status ) )
{
goto errorOpenTransportAddress;
}
pServer->pTDIClient->pTDIClnConnArr =
(pTDIClnConn)ExAllocatePool(
NonPagedPool,
sizeof(TDIClnConn)
);
if( NULL == pServer->pTDIClient->pTDIClnConnArr )
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto errorOpenConnection;
}
pServer->pTDIClient->pTDIClnConnArr->pDevExt = pServer->pTDIClient;
pServer->pTDIClient->pTDIClnConnArr->hConn = INVALID_HANDLE_VALUE;
status = TDIClnOpenConnEndPt( TCP_DEVICE_NAME_W,
&pServer->pTDIClient->pTDIClnConnArr->hConn,
&pServer->pTDIClient->pTDIClnConnArr->pConnFileObj,
pServer->pTDIClient->pTDIClnConnArr);
if( !NT_SUCCESS( status ) )
{
goto errorOpenConnectionEndpoint;
}
KeInitializeEvent(&pServer->pTDIClient->pTDIClnConnArr->AccEvent, NotificationEvent, FALSE);
KeInitializeEvent(&pServer->pTDIClient->pTDIClnConnArr->AccEvent, NotificationEvent, FALSE);
pServer->pTDIClient->pTcpDevObj = IoGetRelatedDeviceObject(pServer->pTDIClient->pAddrFileObj);
status =
TDIClnSetEventHandler (
pServer->pTDIClient->pAddrFileObj,
pServer->pTDIClient->pTcpDevObj,
TDI_EVENT_RECEIVE,
TDISrvEventReceive,
NULL
);
if( !NT_SUCCESS( status ) )
{
goto errorEvent;
}
status =
TDIClnSetEventHandler (
pServer->pTDIClient->pAddrFileObj,
pServer->pTDIClient->pTcpDevObj,
TDI_EVENT_DISCONNECT,
TDISrvEventDisconnect,
NULL
);
if( !NT_SUCCESS( status ) )
{
goto errorEvent;
}
status =
TDIClnSetEventHandler (
pServer->pTDIClient->pAddrFileObj,
pServer->pTDIClient->pTcpDevObj,
TDI_EVENT_ERROR_EX,
TDISrvEventErrorEx,
NULL
);
if( !NT_SUCCESS( status ) )
{
goto errorEvent;
}
status = TDIClnAssocAddr(
pServer->pTDIClient->pTDIClnConnArr->pConnFileObj,
pServer->pTDIClient->pTcpDevObj,
pServer->pTDIClient->hAddr
);
if( !NT_SUCCESS( status ) )
{
goto errorEvent;
}
pIrp = TdiBuildInternalDeviceControlIrp(TDI_ACCEPT,
pServer->pTDIClient->pTcpDevObj,
pServer->pTDIClient->pTDIClnConnArr->pConnFileObj,
&pServer->pTDIClient->pTDIClnConnArr->AccEvent,
&IoStatus
);
if (NULL==pIrp)
{
KdPrint(("Error TdiBuildInternalDeviceControlIrp"));
status = STATUS_INSUFFICIENT_RESOURCES;
goto errorBuildTDIAccept;
}
pServer->pTDIClient->pIrpAccept = pIrp;
status =
TDIClnSetEventHandler( pServer->pTDIClient->pAddrFileObj,
pServer->pTDIClient->pTcpDevObj,
TDI_EVENT_CONNECT,
TDISrvEventConnect,
pServer->pTDIClient->pTDIClnConnArr
);
if (!NT_SUCCESS(status))
{
KdPrint(("Error TDIClnSetEventHandler: TDI_EVENT_CONNECT"));
goto errorBuildTDIAccept;
}
KdPrint(("ServerWorkerThread: Starting... \r\n"));
pEvents[EV_KILLEVENT] = (PVOID)&pDevExt->Tdi_KillEvent;
pEvents[EV_TIMEWAIT] = (PVOID)&pDevExt->Tdi_TimeWait;
pEvents[EV_SEND] = (PVOID)&pDevExt->Tdi_Send;
pEvents[EV_RECV] = (PVOID)&pDevExt->Tdi_Recv;
pEvents[EV_ACC] = (PVOID)&pServer->pTDIClient->pTDIClnConnArr->AccEvent;
pEvents[EV_DIS] = (PVOID)&pServer->pTDIClient->pTDIClnConnArr->DiscEvent;
while(!bDeadThread)
{
switch(KeWaitForMultipleObjects(6, pEvents, WaitAny, Executive, KernelMode, FALSE, NULL, waitBlocks))
{
case EV_ACC:
{
break;
}
case EV_DIS:
{
break;
}
case EV_KILLEVENT:
{
bDeadThread = TRUE;
break;
}
case EV_TIMEWAIT:
{
break;
}
case EV_SEND:
{
break;
}
case EV_RECV:
{
break;
}
}
}
KdPrint(("Server Thread: Exiting...\n") );
errorBuildTDIAccept:
TDIClnDisassocAddr(pServer->pTDIClient->pTDIClnConnArr->pConnFileObj, pServer->pTDIClient->pTcpDevObj);
errorEvent:
if (INVALID_HANDLE_VALUE!=pServer->pTDIClient->pTDIClnConnArr->hConn)
{
ZwClose(pServer->pTDIClient->pTDIClnConnArr->hConn);
pServer->pTDIClient->pTDIClnConnArr->hConn = INVALID_HANDLE_VALUE;
}
if (NULL!=pServer->pTDIClient->pTDIClnConnArr->pConnFileObj)
{
ObDereferenceObject(pServer->pTDIClient->pTDIClnConnArr->pConnFileObj);
pServer->pTDIClient->pTDIClnConnArr->pConnFileObj = NULL;
}
errorOpenConnectionEndpoint:
ExFreePool( pServer->pTDIClient->pTDIClnConnArr );
errorOpenConnection:
if (INVALID_HANDLE_VALUE!=pServer->pTDIClient->hAddr)
{
ZwClose(pServer->pTDIClient->hAddr);
pServer->pTDIClient->hAddr = INVALID_HANDLE_VALUE;
}
if (NULL!=pServer->pTDIClient->pAddrFileObj)
{
ObDereferenceObject(pServer->pTDIClient->pAddrFileObj);
pServer->pTDIClient->pAddrFileObj = NULL;
}
errorOpenTransportAddress:
ExFreePool( pServer->pTDIClient );
errorTDIClient:
ExFreePool( pServer);
(void)PsTerminateSystemThread( STATUS_SUCCESS );
}
Я думаю теперь намного стало понятнее? Возможен ли такой вариан вообще?
Здравствуйте, Zoya_Pobeda, Вы писали:
Если не вдаваться в подробности, то код в принципе рабочий. Мне не вполне ясна сама идея выноса в отдельный поток, но возможно, так удобнее. В этом случае ( использование потока ), нет нужды устанавливать нотификаторы ( это мое частное мнение

), можно обойтись посылкой управляющих IRP и всю работу проводить на PASSIVE_LEVEL, но это дело вкуса

.
У вас в коде 2 бага.
1) при создании потоков нигде не освобождается по ZwClose описатель потоков => утечка
ThreadHandle
Points to a variable that will receive the handle. The driver must close the handle with ZwClose once the handle is no longer in use.
2) при анлоаде никто не ждет завершения потоков, и тут как карта ляжет: кто быстрее кончится — поток или driverunload. Возможен BSOD.
никто не ждет завершения, потому что никто не спрашивает объект потока, так как единственное место, куда пишется хэндл — это структура Server, передающаяся только потоку и им же освобождающаяся
по идее анлоад должен ждать поток после сигнализирования (PVOID)&pDevExt->Tdi_KillEvent;