recv.c

来自「用于嵌入式系统的TCP/IP协议栈」· C语言 代码 · 共 501 行 · 第 1/2 页

C
501
字号
    return -1;  }  /*-------------------------------------------------------------------*/  /* Check destination buffer address and flag parameters.             */  /*-------------------------------------------------------------------*/  if ((dst == NULL) || ((flags & MSG_DONTWAIT) && (flags & MSG_WAITALL)))  {    NetError(sock, EFAULT);    return -1;  }#endif  /*-------------------------------------------------------------------*/  /* Return success if requested data length is zero.                  */  /*-------------------------------------------------------------------*/  if (wanted == 0)    return 0;  /*-------------------------------------------------------------------*/  /* Gain exclusive socket API access and stack internals access.      */  /*-------------------------------------------------------------------*/  if (semPend(sock->api_access, WAIT_FOREVER))  {    NetError(NULL, ENOTSOCK);    return -1;  }  semPend(Net.IntSem, WAIT_FOREVER);  /*-------------------------------------------------------------------*/  /* Check if socket has been shutdown for receives.                   */  /*-------------------------------------------------------------------*/  if (sock->flags & SF_RCV_SHUT)  {    NetError(sock, ESHUTDOWN);    goto recv_exit;  }  /*-------------------------------------------------------------------*/  /* UDP socket read.                                                  */  /*-------------------------------------------------------------------*/  if (sock->type == SOCK_DGRAM)  {    NetBuf *buf;    int datalen;    /*-----------------------------------------------------------------*/    /* Check for illegal flag options.                                 */    /*-----------------------------------------------------------------*/    if (flags & (MSG_OOB | MSG_WAITALL))    {      NetError(sock, EOPNOTSUPP);      goto recv_exit;    }    /*-----------------------------------------------------------------*/    /* If from not NULL, verify fromlen is valid.                      */    /*-----------------------------------------------------------------*/    if (from && (*fromlen != sizeof(struct sockaddr_in)))    {      NetError(sock, EFAULT);      goto recv_exit;    }    /*-----------------------------------------------------------------*/    /* Verify socket is bound.                                         */    /*-----------------------------------------------------------------*/    if (sock->local.sin_port == 0)    {      NetError(sock, EINVAL);      goto recv_exit;    }    /*-----------------------------------------------------------------*/    /* Check if no receive buffers are waiting.                        */    /*-----------------------------------------------------------------*/    if (sock->rq_head == NULL)    {      /*---------------------------------------------------------------*/      /* Return error if operation is non-blocking.                    */      /*---------------------------------------------------------------*/      if ((sock->flags & SF_NONBLKNG) || (flags & MSG_DONTWAIT))      {        NetError(sock, EWOULDBLOCK);        goto recv_exit;      }      /*---------------------------------------------------------------*/      /* Wait for "data received" event.                               */      /*---------------------------------------------------------------*/      NetPendEvent(sock, SE_DATA_RCVD, sock->recv_timeo);      /*---------------------------------------------------------------*/      /* Check for timeout or error while we pended.                   */      /*---------------------------------------------------------------*/      if (sock->error)      {        NetError(sock, sock->error);        goto recv_exit;      }    }    /*-----------------------------------------------------------------*/    /* Copy data to application buffer.                                */    /*-----------------------------------------------------------------*/    buf = sock->rq_head;    datalen = buf->app_len;    rcvd = min(wanted, datalen);    memcpy(dst, buf->app_data, rcvd);    /*-----------------------------------------------------------------*/    /* Output datagram source address if requested.                    */    /*-----------------------------------------------------------------*/    if (from)    {      struct sockaddr_in addr;      Ip *ip = (Ip *)buf->ip_pkt;      Udp *udp = buf->ip_data;      memset(&addr, 0, sizeof(struct sockaddr_in));      addr.sin_family = AF_INET;      addr.sin_port = udp->src_port;      addr.sin_addr.s_addr = ip->src_ip;      *(struct sockaddr_in *)from = addr;    }    /*-----------------------------------------------------------------*/    /* Unless just peeking, extract and recycle queued buffer.         */    /*-----------------------------------------------------------------*/    if ((flags & MSG_PEEK) == FALSE)    {      sock->rq_head = buf->next;      --sock->q_count;      tcpRetBuf(&buf);    }    /*-----------------------------------------------------------------*/    /* Check whether datagram was truncated.                           */    /*-----------------------------------------------------------------*/    if (datalen > wanted)    {      NetError(sock, EMSGSIZE);      rcvd = -1;      goto recv_exit;    }  }  /*-------------------------------------------------------------------*/  /* TCP socket read.                                                  */  /*-------------------------------------------------------------------*/  else  {    int len;    /*-----------------------------------------------------------------*/    /* Check for illegal flag options.                                 */    /*-----------------------------------------------------------------*/    if ((flags & MSG_PEEK) && (flags & MSG_WAITALL))    {      NetError(sock, EOPNOTSUPP);      goto recv_exit;    }    /*-----------------------------------------------------------------*/    /* Ensure urgent data is available if requested.                   */    /*-----------------------------------------------------------------*/    if ((flags & MSG_OOB) && !(sock->flags & SF_OOB_DATA))    {      NetError(sock, EINVAL);      goto recv_exit;    }    /*-----------------------------------------------------------------*/    /* Loop to read the requested number of bytes.                     */    /*-----------------------------------------------------------------*/    for (rcvd = 0; rcvd < wanted; dst = (char *)dst + len, rcvd += len)    {      /*---------------------------------------------------------------*/      /* Attempt to read data from TCP socket.                         */      /*---------------------------------------------------------------*/      len = tcp_recv(sock, dst, wanted - rcvd, flags);      /*---------------------------------------------------------------*/      /* Break if FIN received.                                        */      /*---------------------------------------------------------------*/      if (len == 0)        break;      /*---------------------------------------------------------------*/      /* Check if some data has been previously read.                  */      /*---------------------------------------------------------------*/      if (rcvd)      {        /*-------------------------------------------------------------*/        /* Break to normal exit if error occurred.                     */        /*-------------------------------------------------------------*/        if (len < 0)          break;      }      /*---------------------------------------------------------------*/      /* Else this is first pass through loop.                         */      /*---------------------------------------------------------------*/      else      {        /*-------------------------------------------------------------*/        /* Go to error exit if error occurred.                         */        /*-------------------------------------------------------------*/        if (len < 0)        {          rcvd = -1;          goto recv_exit;        }        /*-------------------------------------------------------------*/        /* Break if retries not requested.                             */        /*-------------------------------------------------------------*/        if ((flags & MSG_WAITALL) == 0)        {          rcvd = len;          break;        }      }    }  }  /*-------------------------------------------------------------------*/  /* Release exclusive API and internals access. Return status code.   */  /*-------------------------------------------------------------------*/recv_exit:  semPost(sock->api_access);  semPost(Net.IntSem);  return rcvd;}/***********************************************************************//*        recv: Receive data from socket                               *//*                                                                     *//*      Inputs: s = socket identifier                                  *//*              dst = pointer to destination buffer                    *//*              wanted = amount of data requested read                 *//*              flags = option flags                                   *//*                                                                     *//***********************************************************************/int (recv)(int s, void *dst, int wanted, int flags){  return recvfrom(s, dst, wanted, flags, 0, 0);}

⌨️ 快捷键说明

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