TDI Listen/Accept Code Problem
От: Bardano  
Дата: 15.03.10 15:45
Оценка:
Good day. I'm trying to write a kernel mode code that uses the TDI interface to accept incoming TCP-connections. And this I can not. Schematic code shown below. Attempt to connect via telnet for the first time succeeds — Irp->IoStatus.Status == STATUS_SUCCESS, but when I try to send / receive data through that connection, I get STATUS_INVALID_DEVICE_STATE (0xC0000184). At this time Process Explorer shows listening socket and the established connection on the same port. Subsequent attempts to connect get Irp->IoStatus.Status == STATUS_CONNECTION_INVALID (0xC000023A). I can not understand why. Maybe I do not understand the mechanism? I would be grateful for the help.

//-------------------------------------------------------------------------------------

/* Listen-socket has two lists — the list of sockets that are waiting to connect — backlog, as I understand it,
** and the list of sockets that are already connected. Access to lists regulates the Queued-SpinLock —
** in order to operate on the list was possible on IRQL <= DISPATCH_LEVEL.
** KernelSocketAccept(__in PKERNEL_SOCKET Socket, __out PKERNEL_SOCKET * AcceptedConnectionSocket) interface function
** waits for SocketConnectedEvent and when connected socket(sockets) appears in the ConnectedSockets list, takes connected
** socket from this list and returns pointer on it in output parameter.
*/

//Kernel-mode socket
typedef struct _KERNEL_SOCKET {

unsigned_native_int Bound;
unsigned_native_int Connected;
unsigned_native_int Listening;

//List pointer
struct _KERNEL_SOCKET * NextSocket;

PDEVICE_OBJECT TransportDeviceObject;
wchar_t * TransportDeviceName;

//File connection to the device to be a transport driver
struct _TransportDeviceFile{
HANDLE Handle;
PFILE_OBJECT Object;
} TransportDeviceFile;

//File of the local address associated with a socket
struct _LocalAddressFile{
HANDLE Handle;
PFILE_OBJECT Object;
} LocalAddressFile;

//List of sockets that are waiting to connect, and a list of sockets for which the connection is established
KERNEL_SOCKET_LIST WaitingSockets;
KERNEL_SOCKET_LIST ConnectedSockets;
//Event, stating that the incoming connection is accepted and connected socket is placed on the list ConnectedSockets
KEVENT SocketConnectedEvent;
} KERNEL_SOCKET, *PKERNEL_SOCKET;

//-------------------------------------------------------------------------------------

//Context structure is transmitted with TDI_ACCEPT IRP
typedef struct _TDI_ACCEPT_IRP_CONTEXT{
//Pointer to Listen-socket
PKERNEL_SOCKET ListeningSocket;
//Pointer to a socket that accepts connection
PKERNEL_SOCKET AcceptSocket;

TDI_CONNECTION_INFORMATION RequestConnectionInformation;
TA_IP_ADDRESS RequestRemoteAddressIPv4;
TA_IP6_ADDRESS RequestRemoteAddressIPv6;
} TDI_ACCEPT_IRP_CONTEXT, *PTDI_ACCEPT_IRP_CONTEXT;

//-------------------------------------------------------------------------------------

//Accept IRP completion routine
IO_COMPLETION_ROUTINE TDIAcceptIRPCompletionRoutine;
static NTSTATUS TDIAcceptIRPCompletionRoutine(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in PVOID Context){

PTDI_ACCEPT_IRP_CONTEXT TDIAcceptIRPContext = (PTDI_ACCEPT_IRP_CONTEXT)Context;

//If pointer TDIAcceptIRPContext is correct
if(TDIAcceptIRPContext){
//If pointers ListeningSocket and AcceptSocket are correct
if(TDIAcceptIRPContext->ListeningSocket && TDIAcceptIRPContext->AcceptSocket){
//If the connection is successfully established
if(Irp->IoStatus.Status == STATUS_SUCCESS){
//Set the appropriate flag in the socket
TDIAcceptIRPContext->AcceptSocket->Connected = true;

//Add a socket to the list of connected sockets of the listening socket
AppendSocketToSocketList(&TDIAcceptIRPContext->ListeningSocket->ConnectedSockets, TDIAcceptIRPContext->AcceptSocket);

//Set the event, stating that the incoming connection is accepted and connected socket is placed in the list ConnectedSockets
KeSetEvent(&TDIAcceptIRPContext->ListeningSocket->SocketConnectedEvent, IO_NO_INCREMENT, FALSE);
}
}

//Release memory
ExFreeToNPagedLookasideList(&KernelSocketsModule.DataBufferLookAsideList, TDIAcceptIRPContext);
}

IoFreeIrp(Irp);

return STATUS_MORE_PROCESSING_REQUIRED;
}

//-------------------------------------------------------------------------------------

//ClientEventConnect
static NTSTATUS TDIClientEventIncomingConnection(IN PVOID TdiEventContext,
IN LONG RemoteAddressLength,
IN PVOID RemoteAddress,
IN LONG UserDataLength,
IN PVOID UserData,
IN LONG OptionsLength,
IN PVOID Options,
OUT CONNECTION_CONTEXT * ConnectionContext,
OUT PIRP * AcceptIrp){

NTSTATUS ThisFunctionResult = STATUS_CONNECTION_REFUSED;
*ConnectionContext = NULL;
*AcceptIrp = NULL;

//TdiEventContext — is a pointer to KERNEL_SOCKET, for which it was installed this Callback procedure
PKERNEL_SOCKET Socket = (PKERNEL_SOCKET)TdiEventContext;

if(RemoteAddress){
if(RemoteAddressLength >= sizeof(TA_IP_ADDRESS)){
if(((PTA_IP_ADDRESS)RemoteAddress)->Address[0].AddressType == TDI_ADDRESS_TYPE_IP){
//Allocate IRP
PIRP AcceptConnectionIRP = IoAllocateIrp(Socket->TransportDeviceObject->StackSize + 1, FALSE);

//If it succeeded
if(AcceptConnectionIRP){
//Allocate context structure in the non-paged pool
PTDI_ACCEPT_IRP_CONTEXT TDIAcceptIRPContext = (PTDI_ACCEPT_IRP_CONTEXT)ExAllocateFromNPagedLookasideList(&KernelSocketsModule.DataBufferLookAsideList);

//If it succeeded
if(TDIAcceptIRPContext){
//Initialize the contextual structure
local_memset(TDIAcceptIRPContext, 0x00, sizeof(TDI_ACCEPT_IRP_CONTEXT));

TDIAcceptIRPContext->RequestRemoteAddressIPv4.TAAddressCount = 1;
TDIAcceptIRPContext->RequestRemoteAddressIPv4.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
TDIAcceptIRPContext->RequestRemoteAddressIPv4.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;

TDIAcceptIRPContext->RequestRemoteAddressIPv4.Address[0].Address[0].in_addr = ((PTA_IP_ADDRESS)RemoteAddress)->Address[0].Address[0].in_addr;
TDIAcceptIRPContext->RequestRemoteAddressIPv4.Address[0].Address[0].sin_port = ((PTA_IP_ADDRESS)RemoteAddress)->Address[0].Address[0].sin_port;

TDIAcceptIRPContext->RequestConnectionInformation.RemoteAddressLength = sizeof(TA_IP_ADDRESS);
TDIAcceptIRPContext->RequestConnectionInformation.RemoteAddress = &TDIAcceptIRPContext->RequestRemoteAddressIPv4;

//Retrieve the socket from the socket, waiting for connection
PKERNEL_SOCKET SocketFromTheWaitingList = TakeSocketFromSocketList(&Socket->WaitingSockets);

//If it succeeded
if(SocketFromTheWaitingList){
//Put pointers to listening socket and a socket that accepts a connection
TDIAcceptIRPContext->ListeningSocket = Socket;
TDIAcceptIRPContext->AcceptSocket = SocketFromTheWaitingList;

//Forming IRP — TDI_ACCEPT
TdiBuildAccept(AcceptConnectionIRP, Socket->TransportDeviceObject, SocketFromTheWaitingList->TransportDeviceFile.Object, TDIAcceptIRPCompletionRoutine, TDIAcceptIRPContext, &TDIAcceptIRPContext->RequestConnectionInformation, NULL);

IoSetNextIrpStackLocation(AcceptConnectionIRP);

//Output function parameters
*ConnectionContext = (CONNECTION_CONTEXT)Socket;
*AcceptIrp = AcceptConnectionIRP;
ThisFunctionResult = STATUS_MORE_PROCESSING_REQUIRED;
}
}
}
}
}
}

return ThisFunctionResult;
}

//-------------------------------------------------------------------------------------

//Module interface function
NTSTATUS KernelSocketListen(__in PKERNEL_SOCKET Socket){

/* Creation of a number of sockets for use in ClientEventConnect — backlog.
** Creation consists of opening the connection to the transport driver — ZwCreateFile()
** and subsequent TDI_ASSOCIATE_ADDRESS.
** Puts these sockets in the list, access to which regulates the Queued-SpinLock —
** in order to operate on the list was possible on IRQL <= DISPATCH_LEVEL.
** This list is tied to the current listening socket — for which this function is called.
** All these actions are fully successful.
*/

/* Then form the IRP — TDI_SET_EVENT_HANDLER with EventType == TDI_EVENT_CONNECT and
** call IoCallDriver(). As PFILE_OBJECT FileObj gives the address file object of this listen socket.
** Returns STATUS_SUCCESS.
*/

/* It seems that in this function everything is working properly */

return ThisFunctionResult;
}

//-------------------------------------------------------------------------------------
tdi network kernel mode
Re: TDI Listen/Accept Code Problem
От: Bardano  
Дата: 15.03.10 20:20
Оценка:
Прошу прощения за избыточные посты. Незнакомый интерфейс форума.
Предыдущие два комментария модератор может удалить.


Вот несколько более полный текст в переводе на русский язык:

Добрый день. Я пытаюсь написать код режима ядра, который использует интерфейс TDI для приёма входящих TCP-соединений. И это не удаётся. Схематический код приведён ниже. Драйвер создает прослушивающий сокет на определённом порту. Попытка подключения с помощью Telnet в первый раз после запуска драйвера успешна — Irp->IoStatus.Status == STATUS_SUCCESS, но когда я пытаюсь отправить/получить данные через это соединение, я получаю STATUS_INVALID_DEVICE_STATE (0xC0000184). При этом Process Explorer показывает прослушивающий сокет и установленное TCP-соединение с этим же портом. Последующие попытки подключения дают Irp->IoStatus.Status == STATUS_CONNECTION_INVALID (0xC000023A). Почему — понять не могу. Может быть, я не понимаю самого механизма? Документация MSDN трудна для понимания. Примеров очень мало. Я был бы признателен за помощь. Возможно, TarasCo сможет дать комментарии?

//-------------------------------------------------------------------------------------

/* Прослушивающий сокет имеет два списка - список сокетов, которые ожидают подключения - Backlog, насколько я понимаю,
** и список сокетов, которые уже подключены. Доступ к спискам регулируется Queued-SpinLock --
** для того, чтобы оперировать списком было возможно при IRQL <= DISPATCH_LEVEL.
** Интерфейсная функция KernelSocketAccept ожидает событие SocketConnectedEvent и, когда подключенный сокет появляется
** в списке ConnectedSockets, изымает этот сокет из этого списка и возвращает указатель на него в выходном параметре.
*/

//Сокет режима ядра
typedef struct _KERNEL_SOCKET {

    //Флаг, показывающий, что сокет связан с локальным адресом
    unsigned_native_int Bound;
    //Для TCP-сокета: флаг, показывающий, что соединение установлено
    unsigned_native_int Connected;
    //Для Listen-сокета: флаг, показывающий, что сокет переведён в режим прослушивания
    unsigned_native_int Listening;

    //Указатель на следующий сокет в односвязном списке сокетов, либо NULL, если этот сокет в списке последний
    struct _KERNEL_SOCKET * NextSocket;

    //Указатель на устройство транспортного драйвера - без увеличения счётчика ссылок
    PDEVICE_OBJECT TransportDeviceObject;
    //Указатель на имя устройства транспортного драйвера
    wchar_t * TransportDeviceName;

    //Файл подключения к устройству подлежащего транспортного драйвера - только для TCP-сокетов
    struct _TransportDeviceFile{
        //Описатель
        HANDLE Handle;
        //И указатель на объект
        PFILE_OBJECT Object;
    } TransportDeviceFile;

    //Файл локального адреса, связанного с сокетом
    struct _LocalAddressFile{
        //Описатель
        HANDLE Handle;
        //И указатель на объект
        PFILE_OBJECT Object;
    } LocalAddressFile;

    /* Список сокетов, ожидающих соединения, и список сокетов, для которых соединение установлено.
    ** Используются только в Listen-сокетах.
    */
    KERNEL_SOCKET_LIST WaitingSockets;
    KERNEL_SOCKET_LIST ConnectedSockets;
    //Событие, сообщающее, что входящее соединение принято и соединённый сокет помещён в список ConnectedSockets - только для Listen-сокетов
    KEVENT SocketConnectedEvent;
} KERNEL_SOCKET, *PKERNEL_SOCKET;

//-------------------------------------------------------------------------------------

//Контекстная структура, передаваемая с TDI_ACCEPT IRP
typedef struct _TDI_ACCEPT_IRP_CONTEXT{
    //Указатель на Listen-сокет
    PKERNEL_SOCKET ListeningSocket;
    //Указатель на сокет, принимающий соединение
    PKERNEL_SOCKET AcceptSocket;

    TDI_CONNECTION_INFORMATION RequestConnectionInformation;
    TA_IP_ADDRESS RequestRemoteAddressIPv4;
    TA_IP6_ADDRESS RequestRemoteAddressIPv6;
} TDI_ACCEPT_IRP_CONTEXT, *PTDI_ACCEPT_IRP_CONTEXT;
//***********************************************************************************************************************************************************************************************************************************************************************

//TDI_ACCEPT IRP Completion Routine
IO_COMPLETION_ROUTINE TDIAcceptIRPCompletionRoutine;
static NTSTATUS TDIAcceptIRPCompletionRoutine(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in PVOID Context){
    /* В качестве указателя на контекст IRP передаётся указатель на блок памяти в нестраничном пуле,
    ** содержащий структуру TDI_ACCEPT_IRP_CONTEXT.
    */
    PTDI_ACCEPT_IRP_CONTEXT TDIAcceptIRPContext = (PTDI_ACCEPT_IRP_CONTEXT)Context;

    //Если указатель TDIAcceptIRPContext корректен
    if(TDIAcceptIRPContext){
        //Если корректны указатели ListeningSocket и AcceptSocket
        if(TDIAcceptIRPContext->ListeningSocket && TDIAcceptIRPContext->AcceptSocket){
            //Если соединение успешно установлено
            if(Irp->IoStatus.Status == STATUS_SUCCESS){
                //Устанавливаем соответствующий флаг в сокете
                TDIAcceptIRPContext->AcceptSocket->Connected = true;

                //Добавляем сокет в список соединенных сокетов прослушивающего сокета
                AppendSocketToSocketList(&TDIAcceptIRPContext->ListeningSocket->ConnectedSockets, TDIAcceptIRPContext->AcceptSocket);

                //Устанавливаем событие, сообщающее, что входящее соединение принято и соединённый сокет помещён в список ConnectedSockets
                KeSetEvent(&TDIAcceptIRPContext->ListeningSocket->SocketConnectedEvent, IO_NO_INCREMENT, FALSE);
            }
        }

        //Освобождаем память, содержащую контекстные данные, в нестраничном пуле
        ExFreeToNPagedLookasideList(&KernelSocketsModule.DataBufferLookAsideList, TDIAcceptIRPContext);
    }

    IoFreeIrp(Irp);

    return STATUS_MORE_PROCESSING_REQUIRED;
}
//***********************************************************************************************************************************************************************************************************************************************************************

//ClientEventConnect
static NTSTATUS TDIClientEventIncomingConnection(IN PVOID TdiEventContext, IN LONG RemoteAddressLength, IN PVOID RemoteAddress, IN LONG UserDataLength, IN PVOID UserData, IN LONG OptionsLength, IN PVOID Options, OUT CONNECTION_CONTEXT * ConnectionContext, OUT PIRP * AcceptIrp){
    //Результат этой функции
    NTSTATUS ThisFunctionResult = STATUS_CONNECTION_REFUSED;

    *ConnectionContext = NULL;
    *AcceptIrp = NULL;

    //TdiEventContext - это указатель на KERNEL_SOCKET, для которого была установлена эта Callback-процедура
    PKERNEL_SOCKET Socket = (PKERNEL_SOCKET)TdiEventContext;

    //Если указатель RemoteAddress корректен
    if(RemoteAddress){
        //Если длина буфера, на который указывает RemoteAddress, корректна
        if(RemoteAddressLength >= sizeof(TA_IP_ADDRESS)){
            //Если корректен тип адреса, указанный в буфере
            if(((PTA_IP_ADDRESS)RemoteAddress)->Address[0].AddressType == TDI_ADDRESS_TYPE_IP){
                //Создаём IRP
                PIRP AcceptConnectionIRP = IoAllocateIrp(Socket->TransportDeviceObject->StackSize + 1, FALSE);

                //Если создать IRP удалось
                if(AcceptConnectionIRP){
                    //Выделяем память для контекстной структуры в нестраничном пуле
                    PTDI_ACCEPT_IRP_CONTEXT TDIAcceptIRPContext = (PTDI_ACCEPT_IRP_CONTEXT)ExAllocateFromNPagedLookasideList(&KernelSocketsModule.DataBufferLookAsideList);

                    //Если выделить память удалось
                    if(TDIAcceptIRPContext){
                        //Инициализируем контекстную структуру
                        local_memset(TDIAcceptIRPContext, 0x00, sizeof(TDI_ACCEPT_IRP_CONTEXT));

                        //В структурах - один адрес
                        TDIAcceptIRPContext->RequestRemoteAddressIPv4.TAAddressCount = 1;
                        //Длина адресов
                        TDIAcceptIRPContext->RequestRemoteAddressIPv4.Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
                        //Тип адресов
                        TDIAcceptIRPContext->RequestRemoteAddressIPv4.Address[0].AddressType = TDI_ADDRESS_TYPE_IP;

                        //Адрес IPv4 - 4 байта
                        TDIAcceptIRPContext->RequestRemoteAddressIPv4.Address[0].Address[0].in_addr = ((PTA_IP_ADDRESS)RemoteAddress)->Address[0].Address[0].in_addr;
                        //Номер порта - 2 байта
                        TDIAcceptIRPContext->RequestRemoteAddressIPv4.Address[0].Address[0].sin_port = ((PTA_IP_ADDRESS)RemoteAddress)->Address[0].Address[0].sin_port;

                        //Указываем длину и адрес удалённого узла
                        TDIAcceptIRPContext->RequestConnectionInformation.RemoteAddressLength = sizeof(TA_IP_ADDRESS);
                        TDIAcceptIRPContext->RequestConnectionInformation.RemoteAddress = &TDIAcceptIRPContext->RequestRemoteAddressIPv4;

                        //Извлекаем сокет из списка сокетов, ожидающих подключения
                        PKERNEL_SOCKET SocketFromTheWaitingList = TakeSocketFromSocketList(&Socket->WaitingSockets);

                        //Если это удалось
                        if(SocketFromTheWaitingList){
                            //Вносим в контекстную структуру указатели на прослушивающий сокет и сокет, принимающий это соединение
                            TDIAcceptIRPContext->ListeningSocket = Socket;
                            TDIAcceptIRPContext->AcceptSocket = SocketFromTheWaitingList;

                            //Формируем IRP - TDI_ACCEPT
                            TdiBuildAccept(AcceptConnectionIRP, Socket->TransportDeviceObject, SocketFromTheWaitingList->TransportDeviceFile.Object, TDIAcceptIRPCompletionRoutine, TDIAcceptIRPContext, &TDIAcceptIRPContext->RequestConnectionInformation, NULL);

                            IoSetNextIrpStackLocation(AcceptConnectionIRP);

                            //Устанавливаем возвращаемое функцией значение, сообщающее, что соединение принимается, и выходные указатели
                            *ConnectionContext = (CONNECTION_CONTEXT)Socket;
                            *AcceptIrp = AcceptConnectionIRP;
                            ThisFunctionResult = STATUS_MORE_PROCESSING_REQUIRED;
                        }
                    }
                }
            }
        }
    }


    /* Возвращаем результат этой функции. Один из следующего:
    **
    ** STATUS_MORE_PROCESSING_REQUIRED - соединение принято, AcceptIrp предоставлен.
    ** STATUS_CONNECTION_REFUSED - соединение отклонено.
    ** STATUS_INSUFFICIENT_RESOURCES - недостаточно ресурсов, соединение будет отклонено.
    */
    return ThisFunctionResult;
}

//-------------------------------------------------------------------------------------

//Интерфейсная функция модуля
NTSTATUS KernelSocketListen(__in PKERNEL_SOCKET Socket){

        /* Создание некоторого числа сокетов для использования в ClientEventConnect - Backlog.
        ** Создание заключается в открытии соединения с транспортом драйвером - ZwCreateFile()
        ** и последующим TDI_ASSOCIATE_ADDRESS.
        ** Помещает эти сокеты в список, доступ к которому регулирует Queued-SpinLock -
        ** для того, чтобы оперировать списком было возможно при IRQL <= DISPATCH_LEVEL.
        ** Этот список привязывается к текущиму прослушивающему сокету - для которого вызывается эта функция.
        ** Все эти действия полностью успешны.
        */

        /* Затем формируем IRP - TDI_SET_EVENT_HANDLER с EventType == TDI_EVENT_CONNECT и
        ** вызываем IoCallDriver(). В качестве PFILE_OBJECT FileObj передаём объект локального адреса, 
    ** связанного с этим прослушивающим сокетом.
        ** Возвращает STATUS_SUCCESS.
        */

        /* Кажется, в этой функции все работает правильно */

        return ThisFunctionResult;
}

//-------------------------------------------------------------------------------------

//Интерфейсная функция модуля
NTSTATUS KernelSocketAccept(__in PKERNEL_SOCKET Socket, __out PKERNEL_SOCKET * AcceptedConnectionSocket){
    //Результат этой функции
    NTSTATUS ThisFunctionResult = STATUS_UNSUCCESSFUL;

    /* Функция ожидает событие SocketConnectedEvent прослушивающего сокета, указатель на который передан.
    ** При возникновении этого события (signaled) изымает сокет из списка подключенных сокетов - ConnectedSockets.
    ** Если в списке сокетов больше нет - сбрасывает событие SocketConnectedEvent. Восполняет список сокетов
    ** ожидающих подключения - WaitingSockets - необходимым количеством сокетов. И возвращает указатель на
    ** подключенный сокет в выходном параметре AcceptedConnectionSocket.
    */

    //Возвращаем результат этой функции
    return ThisFunctionResult;
}

//-------------------------------------------------------------------------------------
Re[2]: TDI Listen/Accept Code Problem
От: TarasCo  
Дата: 16.03.10 14:36
Оценка:
B>Последующие попытки подключения дают Irp->IoStatus.Status == STATUS_CONNECTION_INVALID (0xC000023A).

Это говорит о том, что в запросы TDI_SEND или TDI_RECEIVE вы суете неправильные файлы. Это должны быть KERNEL_SOCKET::TransportDeviceFile.Object и эти файлы должны быть ассоцированы с локальным адресом ( должен быть выполнен запрос TDI_ASSOCIATE_ADDRESS )
Да пребудет с тобою сила
Re[3]: TDI Listen/Accept Code Problem
От: Bardano  
Дата: 16.03.10 17:09
Оценка:
Здравствуйте, TarasCo, Вы писали:

B>>Последующие попытки подключения дают Irp->IoStatus.Status == STATUS_CONNECTION_INVALID (0xC000023A).


TC>Это говорит о том, что в запросы TDI_SEND или TDI_RECEIVE вы суете неправильные файлы. Это должны быть KERNEL_SOCKET::TransportDeviceFile.Object и эти файлы должны быть ассоцированы с локальным адресом ( должен быть выполнен запрос TDI_ASSOCIATE_ADDRESS )


Да, так и происходит. Клиентская часть модуля, включая функции Connect(), Send() и Receive(), работает успешно. В них передаётся именно KERNEL_SOCKET::TransportDeviceFile.Object, и файл локального адреса с подключением ассоциирован. Ошибка, по всей видимости, кроется именно в приведённом коде Listen(), ClientEventConnect() и Accept(). Правильно ли я понимаю механизм? Нет ли у Вас образца работающего кода, реализующего эту функциональность, который можно опубликовать?
Re[3]: TDI Listen/Accept Code Problem
От: Bardano  
Дата: 17.03.10 05:09
Оценка:
Здравствуйте, TarasCo, Вы писали:

B>>Последующие попытки подключения дают Irp->IoStatus.Status == STATUS_CONNECTION_INVALID (0xC000023A).


TC>Это говорит о том, что в запросы TDI_SEND или TDI_RECEIVE вы суете неправильные файлы. Это должны быть KERNEL_SOCKET::TransportDeviceFile.Object и эти файлы должны быть ассоцированы с локальным адресом ( должен быть выполнен запрос TDI_ASSOCIATE_ADDRESS )


Тот же код ошибки (STATUS_CONNECTION_INVALID — 0xC000023A) я вижу, когда пытаюсь применить TDI_SEND к подключению, которое успешно создано и ассоциировано с файлом локального адреса, но до установления TCP-соединения — TDI_CONNECT. Видимо, причина именно в приведённом фрагменте кода.

Достаточно ли для приёма входящих соединений установления callback-процедуры ClientEventConnect() и формирования внутри неё TDI_ACCEPT? Нужно ли посылать TDI_LISTEN? Является ли TDI_LISTEN необходимым элементом этого механизма? Из этого обсуждения с Максимом Шатских, кажется, следует, что TDI_LISTEN можно не использовать. Так ли это?
Re[4]: TDI Listen/Accept Code Problem
От: x64 Россия  
Дата: 17.03.10 15:49
Оценка: 3 (1)
B>Достаточно ли для приёма входящих соединений установления callback-процедуры ClientEventConnect() и формирования внутри неё TDI_ACCEPT?

Да.

B>Нужно ли посылать TDI_LISTEN? Является ли TDI_LISTEN необходимым элементом этого механизма?


Ну я для кого блог-то пишу?
Re[5]: TDI Listen/Accept Code Problem
От: Bardano  
Дата: 17.03.10 17:38
Оценка:
Здравствуйте, x64, Вы писали:

x64>Ну я для кого блог-то пишу?


Так что ж ты раньше-то молчал?
Re[5]: TDI Listen/Accept Code Problem
От: Bardano  
Дата: 17.03.10 22:05
Оценка:
Здравствуйте, x64, Вы писали:

x64>Ну я для кого блог-то пишу?


Да. Спасибо. Это ценное описание. Стало намного яснее. С помощью гугля эта страница не нашлась. Если бы нашлась, не было бы этого поста. Искал по словам "TDI Listen Accept Sample".

Встретил такой абзац:
Помните, что одного активного запроса TDI_LISTEN для высокопроизводительного сервера недостаточно.
Фактически, вы сможете "одновременно" принять столько входящих соединений, сколько создали и отправили запросов TDI_LISTEN.
Таким образом, лучше всего было бы создать и поддерживать пул "слушающих" запросов, но об этом чуть ниже.

Но описание пула "слушающих" запросов ниже не нашел.

Термину "connection endpoint", мне кажется, больше подходит перевод "Конечная точка соединения" — она ведь не удалённая, а локальная.
Re[6]: TDI Listen/Accept Code Problem
От: x64 Россия  
Дата: 17.03.10 22:45
Оценка:
B> Таким образом, лучше всего было бы создать и поддерживать пул "слушающих" запросов, но об этом чуть ниже.
B>Но описание пула "слушающих" запросов ниже не нашел.

Забыл, может быть. Собственно, никакого особого пула и нет. Драйвер, реализующий TDI-сервер, должен создавать и обслуживать его самостоятельно. Грубо говоря, это список заранее выделенных и настроенных IRPs, посланных транспорту, при чём список, разумеется, пополняемый по мере необходимости. Вот и всё, этого тебе хватит для начала.
Re[7]: TDI Listen/Accept Code Problem
От: Bardano  
Дата: 17.03.10 23:02
Оценка:
Здравствуйте, x64, Вы писали:

x64>Собственно, никакого особого пула и нет. Драйвер, реализующий TDI-сервер, должен создавать и обслуживать его самостоятельно. Грубо говоря, это список заранее выделенных и настроенных IRPs, посланных транспорту, при чём список, разумеется, пополняемый по мере необходимости.


Не пойму какие файлы нужно указать в этих IRP. Получается, что файл локального адреса будет один, его нужно ассоциировать с некоторым количеством "конечных точек соединения", а потом для каждой из этих точек создать TDI_LISTEN и отправить транспортному драйверу? Для каждой будет возвращен STATUS_PENDING. И ожидать пока для какой-либо из этих IRP будет завершен? Так что ли? Т.е. один файл локального адреса может быть ассоциирован с несколькими "конечными точками соединения"? Если каждую "конечную точку соединения" связать с отдельным файлом адреса, то и ожидать соединения они будут на разных портах?
Re[8]: TDI Listen/Accept Code Problem
От: x64 Россия  
Дата: 17.03.10 23:05
Оценка: 3 (1)
B>Не пойму какие файлы нужно указать в этих IRP. Получается, что файл локального адреса будет один, его нужно ассоциировать с некоторым количеством "конечных точек соединения", а потом для каждой из этих точек создать TDI_LISTEN и отправить транспортному драйверу? Для каждой будет возвращен STATUS_PENDING. И ожидать пока для какой-либо из этих IRP будет завершен? Так что ли? Т.е. один файл локального адреса может быть ассоциирован с несколькими "конечными точками соединения"? Если каждую "конечную точку соединения" связать с отдельным файлом адреса, то и ожидать соединения они будут на разных портах?

Да.
Re[5]: TDI Listen/Accept Code Problem
От: Bardano  
Дата: 18.03.10 07:25
Оценка:
Здравствуйте, x64, Вы писали:

x64>Ну я для кого блог-то пишу?


Выражаю благодарность x64 за помощь, которая привела к решению моего вопроса.

Приём соединений сделал с помощью пула TDI_LISTEN — так показалось проще.
Re[6]: TDI Listen/Accept Code Problem
От: x64 Россия  
Дата: 18.03.10 07:38
Оценка:
B>Выражаю благодарность...

Блаадарнасть здесь выражается оценками.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.