Receiving Data over a Connection-Oriented Socket

After a Winsock Kernel (WSK) application has connected a connection-oriented socket to a remote transport address it can receive data over the socket. A WSK application can also receive data over a connection-oriented socket that it accepted on a listening socket. A WSK application receives data over a connection-oriented socket by calling the WskReceive function.

The following code example shows how a WSK application can receive data over a connection-oriented socket.

// Prototype for the receive IoCompletion routine
NTSTATUS
  ReceiveComplete(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PVOID Context
    );

// Function to receive data
NTSTATUS
  ReceiveData(
    PWSK_SOCKET Socket,
    PWSK_BUF DataBuffer
    )
{
  PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
  PIRP Irp;
  NTSTATUS Status;

  // Get pointer to the 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,
    ReceiveComplete,
    DataBuffer,  // Use the data buffer for the context
    TRUE,
    TRUE,
    TRUE
    );

  // Initiate the receive operation on the socket
  Status =
    Dispatch->WskReceive(
      Socket,
      DataBuffer,
      0,  // No flags are specified
      Irp
      );

  // Return the status of the call to WskReceive()
  return Status;
}

// Receive IoCompletion routine
NTSTATUS
  ReceiveComplete(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PVOID Context
    )
{
  UNREFERENCED_PARAMETER(DeviceObject);

  PWSK_BUF DataBuffer;
  ULONG ByteCount;

  // Check the result of the receive operation
  if (Irp->IoStatus.Status == STATUS_SUCCESS)
  {
    // Get the pointer to the data buffer
    DataBuffer = (PWSK_BUF)Context;
 
    // Get the number of bytes received
    ByteCount = (ULONG)(Irp->IoStatus.Information);

    // Process the received data
    ...
  }

  // 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;
}

As an alternative to calling the WskReceive function to receive data over a connection-oriented socket, a WSK application can enable the WskReceiveEvent event callback function on the socket. If a WSK application enables the WskReceiveEvent event callback function on a connection-oriented socket, the WSK subsystem calls the socket's WskReceiveEvent event callback function whenever new data is received on the socket. For more information about enabling a connection-oriented socket's WskReceiveEvent event callback function, see Enabling and Disabling Event Callback Functions.

The following code example shows how a WSK application can receive data by the WSK subsystem calling a connection-oriented socket's WskReceiveEvent event callback function.

// A connection-oriented socket's WskReceiveEvent
// event callback function
NTSTATUS WSKAPI
  WskReceiveEvent(
    PVOID SocketContext,
    ULONG Flags,
    PWSK_DATA_INDICATION DataIndication,
    SIZE_T BytesIndicated,
    SIZE_T *BytesAccepted
    )
{
  // Check for a valid data indication
  if (DataIndication != NULL)
  {
    // Loop through the list of data indication structures
    while (DataIndication != NULL)
    {
      // Process the data in the data indication structure
      ...

      // Move to the next data indication structure
      DataIndication = DataIndication->Next;
    }

    // Return status indicating the data was received
    return STATUS_SUCCESS;
  }

  // Error
  else
  {
    // Close the socket
    ...

    // Return success since no data was indicated
    return STATUS_SUCCESS;
  }
}

If a connection-oriented socket's WskReceiveEvent event callback function does not retrieve all of the data contained in the list of WSK_DATA_INDICATION structures pointed to by the DataIndication parameter, it can retain the list for further processing by returning STATUS_PENDING. In this situation, the WSK application must call the WskRelease function to release the list of WSK_DATA_INDICATION structures back to the WSK subsystem after it has completed retrieving all of the data from the structures in the list.

If a connection-oriented socket's WskReceiveEvent event callback function only accepts a portion of the total number of bytes of received data, it must set the variable pointed to by the BytesAccepted parameter to the number of bytes of data that were actually accepted. However, if the socket's WskReceiveEvent event callback function accepts all of the received data, it does not need to set the variable pointed to by the BytesAccepted parameter.