sockimpl.c

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

C
1,411
字号
/*++

Copyright (c) 2005 - 2006, Intel Corporation                                                         
All rights reserved. This program and the accompanying materials                          
are licensed and made available under the terms and conditions of the BSD License         
which accompanies this distribution.  The full text of the license may be found at        
http://opensource.org/licenses/bsd-license.php                                            
                                                                                          
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 

Module Name:

  SockImpl.c

Abstract:

--*/

#include "SockImpl.h"

STATIC
UINT32
SockTcpDataToRcv (
  IN  SOCK_BUFFER   *SockBuffer,
  OUT BOOLEAN       *IsOOB,
  IN  UINT32        BufLen
  );

STATIC
VOID
SockProcessSndToken (
  IN SOCKET *Sock
  );

VOID
SockFreeFoo (
  IN EFI_EVENT Event
  )
{
  return ;
}

STATIC
UINT32
SockTcpDataToRcv (
  IN  SOCK_BUFFER    *SockBuffer,
  OUT BOOLEAN        *IsUrg,
  IN  UINT32         BufLen
  )
/*++

Routine Description:

   Get the length of the data that can be retrieved from the socket
   receive buffer.

Arguments:

  SockBuffer  - Pointer to the socket receive buffer. 
  IsUrg       - Pointer to a BOOLEAN variable. If TRUE the data is OOB.
  BufLen      - The maximum length of the data buffer to store the
                received data in socket layer.

Returns:

  The length of the data can be retreived.

--*/
{
  NET_BUF       *RcvBufEntry;
  UINT32        DataLen;
  TCP_RSV_DATA  *TcpRsvData;
  BOOLEAN       Urg;

  ASSERT (SockBuffer && IsUrg && (BufLen > 0));

  RcvBufEntry = SockBufFirst (SockBuffer);
  ASSERT (RcvBufEntry);

  TcpRsvData  = (TCP_RSV_DATA *) RcvBufEntry->ProtoData;

  *IsUrg      = ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);

  if (*IsUrg && TcpRsvData->UrgLen < RcvBufEntry->TotalSize) {

    DataLen = NET_MIN (TcpRsvData->UrgLen, BufLen);

    if (DataLen < TcpRsvData->UrgLen) {
      TcpRsvData->UrgLen = TcpRsvData->UrgLen - DataLen;
    } else {
      TcpRsvData->UrgLen = 0;
    }

    return DataLen;

  }

  DataLen     = RcvBufEntry->TotalSize;

  RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);

  while ((BufLen > DataLen) && (RcvBufEntry != NULL)) {

    TcpRsvData  = (TCP_RSV_DATA *) RcvBufEntry->ProtoData;

    Urg         = ((TcpRsvData->UrgLen > 0) ? TRUE : FALSE);

    if (*IsUrg != Urg) {
      break;
    }

    if (*IsUrg && TcpRsvData->UrgLen < RcvBufEntry->TotalSize) {

      if (TcpRsvData->UrgLen + DataLen < BufLen) {
        TcpRsvData->UrgLen = 0;
      } else {
        TcpRsvData->UrgLen = TcpRsvData->UrgLen - (BufLen - DataLen);
      }

      return NET_MIN (TcpRsvData->UrgLen + DataLen, BufLen);

    }

    DataLen += RcvBufEntry->TotalSize;

    RcvBufEntry = SockBufNext (SockBuffer, RcvBufEntry);
  }

  DataLen = NET_MIN (BufLen, DataLen);
  return DataLen;
}

VOID
SockSetTcpRxData (
  IN SOCKET     *Sock,
  IN VOID       *TcpRxData,
  IN UINT32     RcvdBytes,
  IN BOOLEAN    IsOOB
  )
/*++

Routine Description:

  Copy data from socket buffer to application provided receive buffer.

Arguments:

  Sock      - Pointer to the socket.
  TcpRxData - Pointer to the application provided receive buffer.
  RcvdBytes - The maximum length of the data can be copied.
  IsOOB     - If TURE the data is OOB, else the data is normal.

Returns:

  None.

--*/
{
  UINT32                  Index;
  UINT32                  CopyBytes;
  UINT32                  OffSet;
  EFI_TCP4_RECEIVE_DATA   *RxData;
  EFI_TCP4_FRAGMENT_DATA  *Fragment;

  RxData  = (EFI_TCP4_RECEIVE_DATA *) TcpRxData;

  OffSet  = 0;

  ASSERT (RxData->DataLength >= RcvdBytes);

  RxData->DataLength  = RcvdBytes;
  RxData->UrgentFlag  = IsOOB;

  for (Index = 0; (Index < RxData->FragmentCount) && (RcvdBytes > 0); Index++) {

    Fragment  = &RxData->FragmentTable[Index];
    CopyBytes = NET_MIN (Fragment->FragmentLength, RcvdBytes);

    NetbufQueCopy (
      Sock->RcvBuffer.DataQueue,
      OffSet,
      CopyBytes,
      Fragment->FragmentBuffer
      );

    Fragment->FragmentLength = CopyBytes;
    RcvdBytes -= CopyBytes;
    OffSet += CopyBytes;
  }
}

UINT32
SockProcessRcvToken (
  IN SOCKET        *Sock,
  IN SOCK_IO_TOKEN *RcvToken
  )
/*++

Routine Description:

  Get received data from the socket layer to the receive token.

Arguments:

  Sock      - Pointer to the socket.
  RcvToken  - Pointer to the application provided receive token.

Returns:

  The length of data received in this token.

--*/
{
  UINT32                 TokenRcvdBytes;
  EFI_TCP4_RECEIVE_DATA  *RxData;
  BOOLEAN                IsUrg;

  ASSERT (Sock);

  ASSERT (SOCK_STREAM == Sock->Type);

  RxData = RcvToken->Packet.RxData;

  TokenRcvdBytes = SockTcpDataToRcv (
                      &Sock->RcvBuffer,
                      &IsUrg,
                      RxData->DataLength
                      );

  //
  // Copy data from RcvBuffer of socket to user
  // provided RxData and set the fields in TCP RxData
  //
  SockSetTcpRxData (Sock, RxData, TokenRcvdBytes, IsUrg);

  SOCK_TRIM_RCV_BUFF (Sock, TokenRcvdBytes);
  SIGNAL_TOKEN (&(RcvToken->Token), EFI_SUCCESS);

  return TokenRcvdBytes;
}

EFI_STATUS
SockProcessTcpSndData (
  IN SOCKET   *Sock,
  IN VOID     *TcpTxData
  )
/*++

Routine Description:

  Process the TCP send data, buffer the tcp txdata and append
  the buffer to socket send buffer,then try to send it.

Arguments:

  Sock      - Pointer to the socket.
  TcpTxData - Pointer to the tcp txdata.

Returns:

  EFI_SUCCESS          - The operation is completed successfully.
  EFI_OUT_OF_RESOURCES - Failed due to resource limit.

--*/
{
  NET_BUF                 *SndData;
  EFI_STATUS              Status;
  EFI_TCP4_TRANSMIT_DATA  *TxData;

  TxData = (EFI_TCP4_TRANSMIT_DATA *) TcpTxData;

  //
  // transform this TxData into a NET_BUFFER
  // and insert it into Sock->SndBuffer
  //
  SndData = NetbufFromExt (
              (NET_FRAGMENT *) TxData->FragmentTable,
              TxData->FragmentCount,
              0,
              0,
              SockFreeFoo,
              NULL
              );

  if (NULL == SndData) {
    SOCK_DEBUG_ERROR (("SockKProcessSndData: Failed to"
      " call NetBufferFromExt\n"));

    return EFI_OUT_OF_RESOURCES;
  }

  NetbufQueAppend (Sock->SndBuffer.DataQueue, SndData);

  //
  // notify the low layer protocol to handle this send token
  //
  if (TxData->Urgent) {
    Status = Sock->ProtoHandler (Sock, SOCK_SNDURG, NULL);

    if (EFI_ERROR (Status)) {
      return Status;
    }
  }

  if (TxData->Push) {
    Status = Sock->ProtoHandler (Sock, SOCK_SNDPUSH, NULL);

    if (EFI_ERROR (Status)) {
      return Status;
    }
  }

  //
  // low layer protocol should really handle the sending
  // process when catching SOCK_SND request
  //
  Status = Sock->ProtoHandler (Sock, SOCK_SND, NULL);

  if (EFI_ERROR (Status)) {
    return Status;
  }

  return EFI_SUCCESS;
}

STATIC
VOID
SockFlushPendingToken (
  IN SOCKET         *Sock,
  IN NET_LIST_ENTRY *PendingTokenList
  )
/*++

Routine Description:

  Flush the tokens in the specific token list.

Arguments:

  Sock              - Pointer to the socket.
  PendingTokenList  - Pointer to the token list to be flushed.

Returns:

  None.

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

  ASSERT (Sock && PendingTokenList);

  while (!NetListIsEmpty (PendingTokenList)) {
    SockToken = NET_LIST_HEAD (
                  PendingTokenList,
                  SOCK_TOKEN,
                  TokenList
                  );

    Token = SockToken->Token;
    SIGNAL_TOKEN (Token, Sock->SockError);

    NetListRemoveEntry (&(SockToken->TokenList));
    NetFreePool (SockToken);
  }
}

STATIC
VOID
SockWakeConnToken (
  IN SOCKET *Sock
  )
/*++

Routine Description:

  Wake up the connection token while the connection is
  successfully established, then try to process any
  pending send token.

Arguments:

  Sock  - Pointer to the socket.

Returns:

  None.

--*/
{
  ASSERT (Sock->ConnectionToken != NULL);

  SIGNAL_TOKEN (Sock->ConnectionToken, EFI_SUCCESS);
  Sock->ConnectionToken = NULL;

  //
  // check to see if some pending send token existed?
  //
  SockProcessSndToken (Sock);
  return ;
}

STATIC
VOID
SockWakeListenToken (
  IN SOCKET *Sock
  )
/*++

Routine Description:

  Wake up the listen token while the connection is
  established successfully.

Arguments:

  Sock  - Pointer to the socket.

Returns:

  None.

--*/
{
  SOCKET                *Parent;
  SOCK_TOKEN            *SockToken;
  EFI_TCP4_LISTEN_TOKEN *ListenToken;

  Parent = Sock->Parent;

  ASSERT (Parent && SOCK_IS_LISTENING (Parent) && SOCK_IS_CONNECTED (Sock));

  if (!NetListIsEmpty (&Parent->ListenTokenList)) {
    SockToken = NET_LIST_HEAD (
                  &Parent->ListenTokenList,
                  SOCK_TOKEN,
                  TokenList
                  );

    ListenToken = (EFI_TCP4_LISTEN_TOKEN *) SockToken->Token;
    ListenToken->NewChildHandle = Sock->SockHandle;

    SIGNAL_TOKEN (&(ListenToken->CompletionToken), EFI_SUCCESS);

    NetListRemoveEntry (&SockToken->TokenList);
    NetFreePool (SockToken);

    NetListRemoveEntry (&Sock->ConnectionList);

    Parent->ConnCnt--;
    SOCK_DEBUG_WARN (("SockWakeListenToken: accept a socket,"
      "now conncnt is %d", Parent->ConnCnt));

    Sock->Parent = NULL;
  }
}

STATIC
VOID
SockWakeRcvToken (
  IN SOCKET *Sock
  )
/*++

Routine Description:

  Wake up the receive token while some data is received.

Arguments:

  Sock  - Pointer to the socket.

Returns:

  None.

--*/
{
  UINT32        RcvdBytes;
  UINT32        TokenRcvdBytes;
  SOCK_TOKEN    *SockToken;
  SOCK_IO_TOKEN *RcvToken;

  ASSERT (Sock->RcvBuffer.DataQueue);

  RcvdBytes = (Sock->RcvBuffer.DataQueue)->BufSize;

  ASSERT (RcvdBytes > 0);

  while (RcvdBytes > 0 && !NetListIsEmpty (&Sock->RcvTokenList)) {

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

    RcvToken        = (SOCK_IO_TOKEN *) SockToken->Token;
    TokenRcvdBytes  = SockProcessRcvToken (Sock, RcvToken);

    if (0 == TokenRcvdBytes) {
      return ;
    }

    NetListRemoveEntry (&(SockToken->TokenList));
    NetFreePool (SockToken);
    RcvdBytes -= TokenRcvdBytes;
  }
}

STATIC
VOID
SockProcessSndToken (
  IN SOCKET *Sock
  )
/*++

Routine Description:

  Process the send token.

Arguments:

  Sock  - Pointer to the socket.

Returns:

  None.

--*/
{
  UINT32                  FreeSpace;
  SOCK_TOKEN              *SockToken;
  UINT32                  DataLen;
  SOCK_IO_TOKEN           *SndToken;
  EFI_TCP4_TRANSMIT_DATA  *TxData;
  EFI_STATUS              Status;

  ASSERT (Sock && (SOCK_STREAM == Sock->Type));

  FreeSpace = SockGetFreeSpace (Sock, SOCK_SND_BUF);

  //
  // to determine if process a send token using
  // socket layer flow control policy
  //
  while ((FreeSpace >= Sock->SndBuffer.LowWater) &&
         !NetListIsEmpty (&Sock->SndTokenList)) {

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

    //
    // process this token
    //
    NetListRemoveEntry (&(SockToken->TokenList));
    NetListInsertTail (
      &(Sock->ProcessingSndTokenList),
      &(SockToken->TokenList)
      );

    //
    // Proceess it in the light of  SockType
    //
    SndToken  = (SOCK_IO_TOKEN *) SockToken->Token;
    TxData    = SndToken->Packet.TxData;

    DataLen = TxData->DataLength;
    Status  = SockProcessTcpSndData (Sock, TxData);

    if (EFI_ERROR (Status)) {
      goto OnError;
    }

    if (DataLen >= FreeSpace) {
      FreeSpace = 0;

    } else {
      FreeSpace -= DataLen;

    }
  }

  return ;

OnError:

  NetListRemoveEntry (&SockToken->TokenList);
  SIGNAL_TOKEN (SockToken->Token, Status);
  NetFreePool (SockToken);
}

SOCKET *
SockCreate (
  IN SOCK_INIT_DATA *SockInitData
  )
/*++

Routine Description:

  Create a socket with initial data SockInitData.

Arguments:

  SockInitData  - Pointer to the initial data of the socket.

Returns:

  Pointer to the newly created socket.

--*/
{
  SOCKET      *Sock;
  SOCKET      *Parent;
  EFI_STATUS  Status;

  ASSERT (SockInitData && SockInitData->ProtoHandler);
  ASSERT (SockInitData->Type == SOCK_STREAM);

  Parent = SockInitData->Parent;

  if (Parent && (Parent->ConnCnt == Parent->BackLog)) {
    SOCK_DEBUG_ERROR (
      ("SockCreate: Socket parent has "
      "reached its connection limit with %d ConnCnt and %d BackLog\n",
      Parent->ConnCnt,
      Parent->BackLog)
      );

    return NULL;
  }

  Sock = NetAllocateZeroPool (sizeof (SOCKET));
  if (NULL == Sock) {

    SOCK_DEBUG_ERROR (("SockCreate: No resource to create a new socket\n"));
    return NULL;
  }

  NetListInit (&Sock->ConnectionList);
  NetListInit (&Sock->ListenTokenList);
  NetListInit (&Sock->RcvTokenList);
  NetListInit (&Sock->SndTokenList);
  NetListInit (&Sock->ProcessingSndTokenList);

  NET_LOCK_INIT (&(Sock->Lock));

  Sock->SndBuffer.DataQueue = NetbufQueAlloc ();
  if (NULL == Sock->SndBuffer.DataQueue) {
    SOCK_DEBUG_ERROR (("SockCreate: No resource to allocate"
      " SndBuffer for new socket\n"));

    goto OnError;
  }

  Sock->RcvBuffer.DataQueue = NetbufQueAlloc ();
  if (NULL == Sock->RcvBuffer.DataQueue) {
    SOCK_DEBUG_ERROR (("SockCreate: No resource to allocate "
      "RcvBuffer for new socket\n"));

    goto OnError;
  }

  Sock->Signature           = SOCK_SIGNATURE;

  Sock->Parent              = Parent;
  Sock->BackLog             = SockInitData->BackLog;
  Sock->ProtoHandler        = SockInitData->ProtoHandler;
  Sock->SndBuffer.HighWater = SockInitData->SndBufferSize;
  Sock->RcvBuffer.HighWater = SockInitData->RcvBufferSize;
  Sock->Type                = SockInitData->Type;
  Sock->DriverBinding       = SockInitData->DriverBinding;
  Sock->State               = SockInitData->State;

  Sock->SockError           = EFI_ABORTED;
  Sock->SndBuffer.LowWater  = SOCK_BUFF_LOW_WATER;
  Sock->RcvBuffer.LowWater  = SOCK_BUFF_LOW_WATER;

  //
  // Install protocol on Sock->SockHandle
  //
  NetCopyMem (
    &(Sock->NetProtocol.TcpProtocol),
    SockInitData->Protocol,
    sizeof (EFI_TCP4_PROTOCOL)
    );

  Status = gBS->InstallMultipleProtocolInterfaces (
                  &Sock->SockHandle,
                  &gEfiTcp4ProtocolGuid,
                  &(Sock->NetProtocol.TcpProtocol),
                  NULL
                  );

  if (EFI_ERROR (Status)) {
    SOCK_DEBUG_ERROR (("SockCreate: Install TCP protocol in "
      "socket failed with %r\n", Status));

    goto OnError;
  }

⌨️ 快捷键说明

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