sockimpl.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,411 行 · 第 1/2 页

C
1,411
字号
  if (Parent != NULL) {
    ASSERT (Parent->BackLog > 0);
    ASSERT (SOCK_IS_LISTENING (Parent));

    //
    // need to add it into Parent->ConnectionList
    // if the Parent->ConnCnt < Parent->BackLog
    //
    Parent->ConnCnt++;

    SOCK_DEBUG_WARN (("SockCreate: Create a new socket and"
      "add to parent, now conncnt is %d\n", Parent->ConnCnt));

    NetListInsertTail (&Parent->ConnectionList, &Sock->ConnectionList);
  }

  return Sock;

OnError:
  if (NULL != Sock) {

    if (NULL != Sock->SndBuffer.DataQueue) {
      NetbufQueFree (Sock->SndBuffer.DataQueue);
    }

    if (NULL != Sock->RcvBuffer.DataQueue) {
      NetbufQueFree (Sock->RcvBuffer.DataQueue);
    }

    NetFreePool (Sock);
  }

  return NULL;
}

VOID
SockDestroy (
  IN SOCKET *Sock
  )
/*++

Routine Description:

  Destroy a socket.

Arguments:

  Sock  - Pointer to the socket.

Returns:

  None.

--*/
{
  VOID        *SockProtocol;
  EFI_GUID    *ProtocolGuid;
  EFI_STATUS  Status;

  ASSERT (SOCK_STREAM == Sock->Type);

  //
  // Flush the completion token buffered
  // by sock and rcv, snd buffer
  //
  if (!SOCK_IS_UNCONFIGURED (Sock)) {

    SockConnFlush (Sock);
    SockSetState (Sock, SO_CLOSED);
    Sock->ConfigureState = SO_UNCONFIGURED;

  }
  //
  // Destory the RcvBuffer Queue and SendBuffer Queue
  //
  NetbufQueFree (Sock->RcvBuffer.DataQueue);
  NetbufQueFree (Sock->SndBuffer.DataQueue);

  //
  // Remove it from parent connection list if needed
  //
  if (Sock->Parent) {

    NetListRemoveEntry (&(Sock->ConnectionList));
    (Sock->Parent->ConnCnt)--;

    SOCK_DEBUG_WARN (("SockDestory: Delete a unaccepted socket from parent"
      "now conncnt is %d\n", Sock->Parent->ConnCnt));

    Sock->Parent = NULL;
  }

  //
  // Set the protocol guid and driver binding handle
  // in the light of Sock->SockType
  //
  ProtocolGuid = &gEfiTcp4ProtocolGuid;

  //
  // Retrieve the protocol installed on this sock
  //
  Status = gBS->OpenProtocol (
                  Sock->SockHandle,
                  ProtocolGuid,
                  &SockProtocol,
                  Sock->DriverBinding,
                  Sock->SockHandle,
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
                  );

  if (EFI_ERROR (Status)) {

    SOCK_DEBUG_ERROR (("SockDestroy: Open protocol installed "
      "on socket failed with %r\n", Status));

    goto FreeSock;
  }

  //
  // Uninstall the protocol installed on this sock
  // in the light of Sock->SockType
  //
  gBS->UninstallMultipleProtocolInterfaces (
        Sock->SockHandle,
        ProtocolGuid,
        SockProtocol,
        NULL
        );

FreeSock:
  NetFreePool (Sock);
  return ;
}

VOID
SockConnFlush (
  IN SOCKET *Sock
  )
/*++

Routine Description:

  Flush the socket.

Arguments:

  Sock  - Pointer to the socket.

Returns:

  None.

--*/
{
  SOCKET  *Child;

  ASSERT (Sock);

  //
  // Clear the flag in this socket
  //
  Sock->Flag = 0;

  //
  // Flush the SndBuffer and RcvBuffer of Sock
  //
  NetbufQueFlush (Sock->SndBuffer.DataQueue);
  NetbufQueFlush (Sock->RcvBuffer.DataQueue);

  //
  // Signal the pending token
  //
  if (Sock->ConnectionToken != NULL) {
    SIGNAL_TOKEN (Sock->ConnectionToken, Sock->SockError);
    Sock->ConnectionToken = NULL;
  }

  if (Sock->CloseToken != NULL) {
    SIGNAL_TOKEN (Sock->CloseToken, Sock->SockError);
    Sock->CloseToken = NULL;
  }

  SockFlushPendingToken (Sock, &(Sock->ListenTokenList));
  SockFlushPendingToken (Sock, &(Sock->RcvTokenList));
  SockFlushPendingToken (Sock, &(Sock->SndTokenList));
  SockFlushPendingToken (Sock, &(Sock->ProcessingSndTokenList));

  //
  // Destroy the pending connection, if it is a listening socket
  //
  if (SOCK_IS_LISTENING (Sock)) {
    while (!NetListIsEmpty (&Sock->ConnectionList)) {
      Child = NET_LIST_HEAD (
                &Sock->ConnectionList,
                SOCKET,
                ConnectionList
                );

      SockDestroyChild (Child);
    }

    Sock->ConnCnt = 0;
  }

  return ;
}

VOID
SockSetState (
  IN SOCKET     *Sock,
  IN SOCK_STATE State
  )
/*++

Routine Description:

  Set the state of the socket.

Arguments:

  Sock  - Pointer to the socket.
  State - The new state to be set.

Returns:

  None.

--*/
{
  Sock->State = State;
}

SOCKET *
SockClone (
  IN SOCKET *Sock
  )
/*++

Routine Description:

  Clone a new socket including its associated protocol control block.

Arguments:

  Sock  - Pointer to the socket to be cloned.

Returns:

  SOCKET * - Pointer to the newly cloned socket.
             If NULL, error condition occurred.

--*/
{
  SOCKET          *ClonedSock;
  SOCK_INIT_DATA  InitData;

  InitData.BackLog        = Sock->BackLog;
  InitData.Parent         = Sock;
  InitData.State          = Sock->State;
  InitData.ProtoHandler   = Sock->ProtoHandler;
  InitData.Type           = Sock->Type;
  InitData.RcvBufferSize  = Sock->RcvBuffer.HighWater;
  InitData.SndBufferSize  = Sock->SndBuffer.HighWater;
  InitData.DriverBinding  = Sock->DriverBinding;
  InitData.Protocol       = &(Sock->NetProtocol);

  ClonedSock              = SockCreate (&InitData);

  if (NULL == ClonedSock) {
    SOCK_DEBUG_ERROR (("SockClone: no resource to create a cloned sock\n"));
    return NULL;
  }

  NetCopyMem (
    ClonedSock->ProtoReserved,
    Sock->ProtoReserved,
    PROTO_RESERVED_LEN
    );

  SockSetState (ClonedSock, SO_CONNECTING);
  ClonedSock->ConfigureState = Sock->ConfigureState;

  return ClonedSock;
}

VOID
SockConnEstablished (
  IN SOCKET *Sock
  )
/*++

Routine Description:

  Called by the low layer protocol to indicate the socket
  a connection is established. This function just changes
  the socket's state to SO_CONNECTED and signals the token
  used for connection establishment.

Arguments:

  Sock  - Pointer to the socket associated with the established
          connection.

Returns:

  None.

--*/
{

  ASSERT (SO_CONNECTING == Sock->State);

  SockSetState (Sock, SO_CONNECTED);

  if (NULL == Sock->Parent) {
    SockWakeConnToken (Sock);
  } else {
    SockWakeListenToken (Sock);
  }

  return ;
}

VOID
SockConnClosed (
  IN SOCKET *Sock
  )
/*++

Routine Description:

  Called by the low layer protocol to indicate the connection
  is closed. This function flushes the socket, sets the state 
  to SO_CLOSED and signals the close token.

Arguments:

  Sock  - Pointer to the socket associated with the closed
          connection.

Returns:

  None.

--*/
{
  if (Sock->CloseToken) {
    SIGNAL_TOKEN (Sock->CloseToken, EFI_SUCCESS);
    Sock->CloseToken = NULL;
  }

  SockConnFlush (Sock);
  SockSetState (Sock, SO_CLOSED);

  if (Sock->Parent != NULL) {
    SockDestroyChild (Sock);
  }

}

VOID
SockDataSent (
  IN SOCKET     *Sock,
  IN UINT32     Count
  )
/*++

Routine Description:

  Called by low layer protocol to indicate that some
  data is sent or processed. This function trims the
  sent data in the socket send buffer, signals the
  data token if proper

Arguments:

  Sock  - Pointer to the socket.
  Count - The length of the data processed or sent, in bytes.

Returns:

  None.

--*/
{
  SOCK_TOKEN            *SockToken;
  SOCK_COMPLETION_TOKEN *SndToken;

  ASSERT (!NetListIsEmpty (&Sock->ProcessingSndTokenList));
  ASSERT (Count <= (Sock->SndBuffer.DataQueue)->BufSize);

  NetbufQueTrim (Sock->SndBuffer.DataQueue, Count);

  //
  // To check if we can signal some snd token in this socket
  //
  while (Count > 0) {
    SockToken = NET_LIST_HEAD (
                  &(Sock->ProcessingSndTokenList),
                  SOCK_TOKEN,
                  TokenList
                  );

    SndToken = SockToken->Token;

    if (SockToken->RemainDataLen <= Count) {

      NetListRemoveEntry (&(SockToken->TokenList));
      SIGNAL_TOKEN (SndToken, EFI_SUCCESS);
      Count -= SockToken->RemainDataLen;
      NetFreePool (SockToken);
    } else {

      SockToken->RemainDataLen -= Count;
      Count = 0;
    }
  }

  //
  // to judge if we can process some send token in
  // Sock->SndTokenList, if so process those send token
  //
  SockProcessSndToken (Sock);
  return ;
}

UINT32
SockGetDataToSend (
  IN SOCKET      *Sock,
  IN UINT32      Offset,
  IN UINT32      Len,
  IN UINT8       *Dest
  )
/*++

Routine Description:

  Called by the low layer protocol to copy some data in socket send
  buffer starting from the specific offset to a buffer provided by
  the caller.

Arguments:

  Sock    - Pointer to the socket.
  Offset  - The start point of the data to be copied.
  Len     - The length of the data to be copied.
  Dest    - Pointer to the destination to copy the data.

Returns:

  The data size copied.

--*/
{
  ASSERT (Sock && SOCK_STREAM == Sock->Type);

  return NetbufQueCopy (
          Sock->SndBuffer.DataQueue,
          Offset,
          Len,
          Dest
          );
}

VOID
SockDataRcvd (
  IN SOCKET    *Sock,
  IN NET_BUF   *NetBuffer,
  IN UINT32    UrgLen
  )
/*++

Routine Description:

  Called by the low layer protocol to deliver received data
  to socket layer. This function will append the data to the
  socket receive buffer, set ther urgent data length and then
  check if any receive token can be signaled.

Arguments:

  Sock      - Pointer to the socket.
  NetBuffer - Pointer to the buffer that contains the received data.
  UrgLen    - The length of the urgent data in the received data.

Returns:

  None.

--*/
{
  ASSERT (Sock && Sock->RcvBuffer.DataQueue &&
    UrgLen <= NetBuffer->TotalSize);

  NET_GET_REF (NetBuffer);

  ((TCP_RSV_DATA *) (NetBuffer->ProtoData))->UrgLen = UrgLen;

  NetbufQueAppend (Sock->RcvBuffer.DataQueue, NetBuffer);

  SockWakeRcvToken (Sock);
  return ;
}

UINT32
SockGetFreeSpace (
  IN SOCKET  *Sock,
  IN UINT32  Which
  )
/*++

Routine Description:

  Get the length of the free space of the specific socket buffer.

Arguments:

  Sock  - Pointer to the socket.
  Which - Flag to indicate which socket buffer to check, either
          send buffer or receive buffer.

Returns:

  The length of the free space, in bytes.

--*/
{
  UINT32      BufferCC;
  SOCK_BUFFER *SockBuffer;

  ASSERT (Sock && ((SOCK_SND_BUF == Which) || (SOCK_RCV_BUF == Which)));

  if (SOCK_SND_BUF == Which) {
    SockBuffer = &(Sock->SndBuffer);
  } else {
    SockBuffer = &(Sock->RcvBuffer);
  }

  BufferCC = (SockBuffer->DataQueue)->BufSize;

  if (BufferCC >= SockBuffer->HighWater) {

    return 0;
  }

  return SockBuffer->HighWater - BufferCC;
}

VOID
SockRcvdErr (
  IN SOCKET       *Sock,
  IN EFI_STATUS   Error
  )
/*++

Routine Description:

  Signal the receive token with the specific error or
  set socket error code after error is received.

Arguments:

  Sock  - Pointer to the socket.
  Error - The error code received.

Returns:

  None.

--*/
{
  SOCK_TOKEN  *SockToken;

  if (!NetListIsEmpty (&Sock->RcvTokenList)) {

    SockToken = NET_LIST_HEAD (
                  &Sock->RcvTokenList,
                  SOCK_TOKEN,
                  TokenList
                  );

    NetListRemoveEntry (&SockToken->TokenList);

    SIGNAL_TOKEN (SockToken->Token, Error);

    NetFreePool (SockToken);
  } else {

    SOCK_ERROR (Sock, Error);
  }
}

VOID
SockNoMoreData (
  IN SOCKET *Sock
  )
/*++

Routine Description:

  Called by the low layer protocol to indicate that there
  will be no more data from the communication peer. This
  function set the socket's state to SO_NO_MORE_DATA and
  signal all queued IO tokens with the error status
  EFI_CONNECTION_FIN.

Arguments:

  Sock  - Pointer to the socket.

Returns:

  None.

--*/
{
  EFI_STATUS  Err;

  SOCK_NO_MORE_DATA (Sock);

  if (!NetListIsEmpty (&Sock->RcvTokenList)) {

    ASSERT (0 == GET_RCV_DATASIZE (Sock));

    Err = Sock->SockError;

    SOCK_ERROR (Sock, EFI_CONNECTION_FIN);

    SockFlushPendingToken (Sock, &Sock->RcvTokenList);

    SOCK_ERROR (Sock, Err);

  }

}

NET_BUF *
SockBufFirst (
  IN SOCK_BUFFER *Sockbuf
  )
/*++

Routine Description:

  Get the first buffer block in the specific socket buffer.

Arguments:

  Sockbuf - Pointer to the socket buffer.

Returns:

  Pointer to the first buffer in the queue. NULL if the queue is empty.

--*/
{
  NET_LIST_ENTRY  *NetbufList;

  NetbufList = &(Sockbuf->DataQueue->BufList);

  if (NetListIsEmpty (NetbufList)) {
    return NULL;
  }

  return NET_LIST_HEAD (NetbufList, NET_BUF, List);
}

NET_BUF *
SockBufNext (
  IN SOCK_BUFFER *Sockbuf,
  IN NET_BUF     *SockEntry
  )
/*++

Routine Description:

  Get the next buffer block in the specific socket buffer.

Arguments:

  Sockbuf   - Pointer to the socket buffer.
  SockEntry - Pointer to the buffer block prior to the
              required one.

Returns:

  Pointer to the buffer block next to SockEntry. NULL if SockEntry is the tail or head entry.

--*/
{
  NET_LIST_ENTRY  *NetbufList;

  NetbufList = &(Sockbuf->DataQueue->BufList);

  if ((SockEntry->List.ForwardLink == NetbufList) ||
      (SockEntry->List.BackLink == &SockEntry->List) ||
      (SockEntry->List.ForwardLink == &SockEntry->List)
      ) {

    return NULL;
  }

  return NET_LIST_USER_STRUCT (SockEntry->List.ForwardLink, NET_BUF, List);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?