Escutando e aceitando conexões de entrada
Depois que um aplicativo WSK (Winsock Kernel) associa um soquete de escuta a um endereço de transporte local, o soquete começa a escutar conexões de entrada de endereços de transporte remoto. Um aplicativo WSK pode aceitar uma conexão de entrada em um soquete de escuta chamando a função WskAccept . O IRP que o aplicativo passa para a função WskAccept é enfileirado até que uma conexão de entrada chegue.
O exemplo de código a seguir mostra como um aplicativo WSK pode aceitar uma conexão de entrada chamando a função WskAccept .
// Prototype for the accept IoCompletion routine
NTSTATUS
AcceptComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
);
// Function to accept an incoming connection
NTSTATUS
AcceptConnection(
PWSK_SOCKET Socket,
PVOID AcceptSocketContext,
PWSK_CLIENT_CONNECTION_DISPATCH AcceptSocketDispatch
)
{
PWSK_PROVIDER_LISTEN_DISPATCH Dispatch;
PIRP Irp;
NTSTATUS Status;
// Get pointer to the socket's provider dispatch structure
Dispatch =
(PWSK_PROVIDER_LISTEN_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,
AcceptComplete,
AcceptSocketContext,
TRUE,
TRUE,
TRUE
);
// Initiate the accept operation on the socket
Status =
Dispatch->WskAccept(
Socket,
0, // No flags
AcceptSocketContext,
AcceptSocketDispatch,
NULL,
NULL,
Irp
);
// Return the status of the call to WskAccept()
return Status;
}
// The accept IoCompletion routine
NTSTATUS
AcceptComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
)
{
UNREFERENCED_PARAMETER(DeviceObject);
PWSK_SOCKET Socket;
PVOID AcceptSocketContext;
// Check the result of the accept operation
if (Irp->IoStatus.Status == STATUS_SUCCESS)
{
// Get the accepted socket object from the IRP
Socket = (PWSK_SOCKET)(Irp->IoStatus.Information);
// Get the accepted socket's context
AcceptSocketContext = Context;
// Perform the next operation on the accepted 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;
}
Como alternativa para chamar a função WskAccept para aceitar conexões de entrada em um soquete de escuta, um aplicativo WSK pode habilitar a função de retorno de chamada de evento WskAcceptEvent no soquete . Se um aplicativo WSK habilitar a função de retorno de chamada de evento WskAcceptEvent em um soquete de escuta, o subsistema WSK chamará a função de retorno de chamada de evento WskAcceptEvent do soquete sempre que uma nova conexão de entrada for aceita no soquete. Para obter mais informações sobre como habilitar a função de retorno de chamada de evento WskAcceptEvent de um soquete de escuta, consulte Habilitando e desabilitando funções de retorno de chamada de evento.
O exemplo de código a seguir mostra como um aplicativo WSK pode aceitar uma conexão de entrada pelo subsistema WSK chamando a função de retorno de chamada de evento WskAcceptEvent de um soquete de escuta.
// Dispatch table of event callback functions for accepted sockets
const WSK_CLIENT_CONNECTION_DISPATCH ConnectionDispatch =
{
.
. // Function pointers for the event callback functions
.
};
// Pool tag used for allocating the socket context
#define SOCKET_CONTEXT_POOL_TAG 'tpcs'
// A listening socket's WskAcceptEvent event callback function
NTSTATUS WSKAPI
WskAcceptEvent(
PVOID SocketContext,
ULONG Flags,
PSOCKADDR LocalAddress,
PSOCKADDR RemoteAddress,
PWSK_SOCKET AcceptSocket,
PVOID *AcceptSocketContext,
CONST WSK_CLIENT_CONNECTION_DISPATCH **AcceptSocketDispatch
)
{
PWSK_APP_SOCKET_CONTEXT SocketContext;
// Check for a valid new socket
if (AcceptSocket != NULL)
{
// Allocate the socket context
SocketContext =
(PWSK_APP_SOCKET_CONTEXT)
ExAllocatePoolWithTag(
NonPagedPool,
sizeof(WSK_APP_SOCKET_CONTEXT),
SOCKET_CONTEXT_POOL_TAG
);
// Check result of allocation
if (SocketContext == NULL)
{
// Reject the socket
return STATUS_REQUEST_NOT_ACCEPTED;
}
// Initialize the socket context
SocketContext->Socket = AcceptSocket;
...
// Set the accepted socket's client context
*AcceptSocketContext = SocketContext;
// Set the accepted socket's dispatch table of callback functions
*AcceptSocketDispatch = ConnectionDispatch;
// Perform additional operations on the accepted socket
...
// Return status indicating that the socket was accepted
return STATUS_SUCCESS:
}
// Error with listening socket
else
{
// Handle error
...
// Return status indicating that no socket was accepted
return STATUS_REQUEST_NOT_ACCEPTED;
}
}
Um aplicativo WSK pode configurar um soquete de escuta para aceitar condicionalmente conexões de entrada recebidas no soquete. Um aplicativo WSK permite o modo de aceitação condicional em um soquete de escuta definindo a opção de soquete SO_CONDITIONAL_ACCEPT para o soquete antes de associar o soquete a um endereço de transporte local. Para obter mais informações sobre como definir opções de soquete, consulte Executando operações de controle em um soquete.
Se o modo de aceitação condicional estiver habilitado em um soquete de escuta, o subsistema WSK primeiro chamará a função de retorno de chamada de evento WskInspectEvent do soquete sempre que uma nova solicitação de conexão de entrada for recebida no soquete. A função de retorno de chamada de evento WskInspectEvent de um soquete pode inspecionar a solicitação de conexão de entrada para determinar se a solicitação deve ser aceita ou rejeitada. Para aceitar a solicitação, a função de retorno de chamada de evento WskInspectEvent do soquete retorna InspectAccept. Para rejeitar a solicitação, a função de retorno de chamada de evento WskInspectEvent do soquete retorna InspectReject. Se a função de retorno de chamada de evento WskInspectEvent de um soquete não puder determinar imediatamente se a solicitação deve ser aceita ou rejeitada, ela retornará InspectPend. Nessa situação, um aplicativo WSK deve chamar a função WskInspectComplete depois de concluir o processo de inspeção para a solicitação de conexão de entrada. Se uma solicitação de conexão de entrada for descartada antes que a conexão de soquete seja totalmente estabelecida, o subsistema WSK chamará a função de retorno de chamada de evento WskAbortEvent do aplicativo WSK.
O exemplo de código a seguir mostra como um aplicativo WSK pode inspecionar uma solicitação de conexão de entrada pelo subsistema WSK chamando a função de retorno de chamada de evento WskInspectEvent do soquete de escuta.
// Inspect ID for a pending inspection
WSK_INSPECT_ID PendingInspectID
// A listening socket's WskInspectEvent event callback function
WSK_INSPECT_ACTION WSKAPI
WskInspectEvent(
PVOID SocketContext,
PSOCKADDR LocalAddress,
PSOCKADDR RemoteAddress,
PWSK_INSPECT_ID InspectID
)
{
// Check for a valid inspect ID
if (InspectID != NULL)
{
// Inspect local and/or remote address of the incoming
// connection request to determine if the connection should
// be accepted or rejected.
...
// If the incoming connection should be accepted
if (...)
{
// Return status indicating that the incoming
// connection request was accepted
return InspectAccept;
}
// If the incoming connection should be rejected
else if (...)
{
// Return status indicating that the incoming
// connection request was rejected
return InspectReject;
}
// Cannot determine immediately
else
{
// Save the inspect ID while the inspection is pending.
// This will be passed to WskInspectComplete when the
// inspection process is completed.
PendingInspectID = *InspectID;
// Return status indicating that the result of the
// inspection process for the incoming connection
// request is pending
return InspectPend;
}
}
// Error with listening socket
else
{
// Handle error
...
// Return status indicating that a socket was not accepted
return InspectReject;
}
}
// A listening socket's WskAbortEvent event callback function
NTSTATUS WSKAPI
WskAbortEvent(
PVOID SocketContext,
PWSK_INSPECT_ID InspectID
)
{
// Terminate the inspection for the incoming connection
// request with a matching inspect ID. To test for a matching
// inspect ID, the contents of the WSK_INSPECT_ID structures
// must be compared, not the pointers to the structures.
...
}
Se um aplicativo WSK determinar que aceitará uma solicitação de conexão de entrada em um soquete de escuta que tenha o modo de aceitação condicional habilitado, a conexão de entrada será estabelecida e poderá ser aceita normalmente pela chamada do aplicativo para a função WskAccept ou pelo subsistema WSK que chama a função de retorno de chamada de evento WskAcceptEvent do soquete , conforme descrito anteriormente.