Включение и отключение функций обратного вызова событий
Приложение ядра Winsock (WSK) может реализовывать функции обратного вызова событий, которые подсистема WSK вызывает асинхронно, чтобы уведомлять приложение о возникновении определенных событий в сокете. Приложение WSK может предоставлять подсистеме WSK структуру таблицы диспетчеризации клиента, когда оно создает сокет или принимает сокет в сокете для прослушивания. Эта таблица диспетчеризации содержит указатели на функции обратного вызова событий приложения WSK для нового сокета. Если приложение WSK не реализует функции обратного вызова событий для определенного сокета, ему не нужно предоставлять структуру таблицы диспетчеризации клиента подсистеме WSK для этого сокета.
Все функции обратного вызова событий сокета, за исключением функций обратного вызова событий WskInspectEvent и WskAbortEvent прослушивающего сокета, можно включить или отключить с помощью параметра сокета SO_WSK_EVENT_CALLBACK . Приложение WSK может одновременно включить несколько функций обратного вызова событий в сокете. Однако приложение WSK должно отключить каждую функцию обратного вызова события по отдельности.
В следующем примере кода показано, как приложение WSK может использовать параметр сокета SO_WSK_EVENT_CALLBACK для включения функций обратного вызова событий WskDisconnectEvent и WskReceiveEvent в сокете, ориентированном на подключение.
// Function to enable the WskDisconnectEvent and WskReceiveEvent
// event callback functions on a connection-oriented socket
NTSTATUS
EnableDisconnectAndRecieveCallbacks(
PWSK_SOCKET Socket
)
{
PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
WSK_EVENT_CALLBACK_CONTROL EventCallbackControl;
NTSTATUS Status;
// Get pointer to the socket's provider dispatch structure
Dispatch =
(PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);
// Specify the WSK NPI identifier
EventCallbackControl.NpiId = &NPI_WSK_INTERFACE_ID;
// Set the event flags for the event callback functions that
// are to be enabled on the socket
EventCallbackControl.EventMask =
WSK_EVENT_DISCONNECT | WSK_EVENT_RECEIVE;
// Initiate the control operation on the socket
Status =
Dispatch->WskControlSocket(
Socket,
WskSetOption,
SO_WSK_EVENT_CALLBACK,
SOL_SOCKET,
sizeof(WSK_EVENT_CALLBACK_CONTROL),
&EventCallbackControl,
0,
NULL,
NULL,
NULL // No IRP for this control operation
);
// Return the status of the call to WskControlSocket()
return Status;
}
В следующем примере кода показано, как приложение WSK может использовать параметр сокета SO_WSK_EVENT_CALLBACK для отключения функций обратного вызова событий WskReceiveEvent в сокете, ориентированном на подключение.
// Prototype for the disable disconnect IoCompletion routine
NTSTATUS
DisableDisconnectComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
);
// Function to disable the WskDisconnectEvent event
// callback functions on a connection-oriented socket
NTSTATUS
DisableDisconnectCallback(
PWSK_SOCKET Socket
)
{
PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
PIRP Irp;
WSK_EVENT_CALLBACK_CONTROL EventCallbackControl;
NTSTATUS Status;
// Get pointer to the socket's provider dispatch structure
Dispatch =
(PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);
// Allocate an IRP
Irp =
IoAllocateIrp(
1,
FALSE
);
// Check result
if (!Irp)
{
// Return error
return STATUS_INSUFFICIENT_RESOURCES;
}
// Set the completion routine for the IRP
IoSetCompletionRoutine(
Irp,
DisableDisconnectComplete,
Socket, // Use the socket object for the context
TRUE,
TRUE,
TRUE
);
// Specify the WSK NPI identifier
EventCallbackControl.NpiId = &NPI_WSK_INTERFACE_ID;
// Set the event flag for the event callback function that
// is to be disabled on the socket along with the disable flag
EventCallbackControl.EventMask =
WSK_EVENT_DISCONNECT | WSK_EVENT_DISABLE;
// Initiate the control operation on the socket
Status =
Dispatch->WskControlSocket(
Socket,
WskSetOption,
SO_WSK_EVENT_CALLBACK,
SOL_SOCKET,
sizeof(WSK_EVENT_CALLBACK_CONTROL),
&EventCallbackControl,
0,
NULL,
NULL,
Irp
);
// Return the status of the call to WskControlSocket()
return Status;
}
// Disable disconnect IoCompletion routine
NTSTATUS
DisableDisconnectComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
)
{
UNREFERENCED_PARAMETER(DeviceObject);
PWSK_SOCKET Socket;
// Check the result of the control operation
if (Irp->IoStatus.Status == STATUS_SUCCESS)
{
// The WskDisconnectEvent event callback
// function is now disabled
// Get the socket object from the context
Socket = (PWSK_SOCKET)Context;
// Perform the next operation on the socket
...
}
// Error status
else
{
// Handle error
...
}
// Free the IRP
IoFreeIrp(Irp);
// Always return STATUS_MORE_PROCESSING_REQUIRED to
// terminate the completion processing of the IRP.
return STATUS_MORE_PROCESSING_REQUIRED;
}
Для прослушивания сокетов функции обратного вызова событий WskInspectEvent и WskAbortEvent включены только в том случае, если приложение WSK включает режим условного принятия для сокета. Приложение WSK включает режим условного принятия для прослушивающего сокета, задавая параметр SO_CONDITIONAL_ACCEPT сокета для сокета перед привязкой сокета к локальному адресу транспорта. Дополнительные сведения о настройке параметров сокета см. в разделе Выполнение управляющих операций в сокете.
После включения режима условного принятия для прослушивающего сокета функции обратного вызова событий WskInspectEvent и WskAbortEvent в сокете не могут быть отключены. Дополнительные сведения об условном принятии входящих подключений в прослушивающих сокетах см. в разделах Прослушивание и Прием входящих подключений.
Прослушивающий сокет может автоматически включать функции обратного вызова событий в сокетах, ориентированных на подключение, которые принимаются функцией обратного вызова событий WskAcceptEvent прослушивающего сокета. Приложение WSK автоматически включает эти функции обратного вызова, включив функции обратного вызова событий сокета, ориентированных на подключение, в прослушивающем сокете. Дополнительные сведения об этом процессе см. в разделе SO_WSK_EVENT_CALLBACK.
Если приложение WSK всегда включает определенные функции обратного вызова событий для каждого создаваемого сокета, приложение может настроить подсистему WSK для автоматического включения этих функций обратного вызова событий с помощью операции управления WSK_SET_STATIC_EVENT_CALLBACKS клиента. Функции обратного вызова событий, включенные таким образом, всегда включены и не могут быть отключены или повторно включены приложением WSK позже. Если приложение WSK всегда включает определенные функции обратного вызова событий в каждом создаваемом сокете, приложение должно использовать этот метод для автоматического включения этих функций обратного вызова событий, так как это обеспечит гораздо более высокую производительность.
В следующем примере кода показано, как приложение WSK может использовать операцию WSK_SET_STATIC_EVENT_CALLBACKS клиентского управления для автоматического включения функции обратного вызова событий WskReceiveFromEvent в сокетах датаграмм и функции обратного вызова событий WskReceiveEvent в сокетах, ориентированных на подключение.
// Function to set static event callbacks
NTSTATUS
SetStaticEventCallbacks(
PWSK_APP_BINDING_CONTEXT BindingContext,
)
{
WSK_EVENT_CALLBACK_CONTROL EventCallbackControl;
NTSTATUS Status;
// Specify the WSK NPI identifier
EventCallbackControl.NpiId = &NPI_WSK_INTERFACE_ID;
// Set the event flags for the event callback functions that
// are to be automatically enabled on every new socket
EventCallbackControl.EventMask =
WSK_EVENT_RECEIVE_FROM | WSK_EVENT_RECEIVE;
// Perform client control operation
Status =
BindingContext->
WskProviderDispatch->
WskControlClient(
BindingContext->WskClient,
WSK_SET_STATIC_EVENT_CALLBACKS,
sizeof(WSK_EVENT_CALLBACK_CONTROL),
&EventCallbackControl,
0,
NULL,
NULL,
NULL // No IRP for this control operation
);
// Return status of client control operation
return Status;
}
Если приложение WSK использует операцию управления WSK_SET_STATIC_EVENT_CALLBACKS клиента для автоматического включения определенных функций обратного вызова событий, это необходимо сделать перед созданием сокетов.