Skip to content
Snippets Groups Projects
recvfrom.c 32.1 KiB
Newer Older
 *
 * Parameters:
 *   sockfd   Socket descriptor of socket
 *   buf      Buffer to receive data
 *   len      Length of buffer
 *   flags    Receive flags
patacongo's avatar
patacongo committed
 *   from     Address of source (may be NULL)
 *   fromlen  The length of the address structure
 *
 * Returned Value:
 *   On success, returns the number of characters sent.  On  error,
 *   -1 is returned, and errno is set appropriately:
 *
 *   EAGAIN
 *     The socket is marked non-blocking and the receive operation would block,
 *     or a receive timeout had been set and the timeout expired before data
 *     was received.
 *   EBADF
 *     The argument sockfd is an invalid descriptor.
 *   ECONNREFUSED
 *     A remote host refused to allow the network connection (typically because
 *     it is not running the requested service).
 *   EFAULT
 *     The receive buffer pointer(s) point outside the process's address space.
 *   EINTR
 *     The receive was interrupted by delivery of a signal before any data were
 *     available.
 *   EINVAL
 *     Invalid argument passed.
 *   ENOMEM
patacongo's avatar
patacongo committed
 *     Could not allocate memory.
 *   ENOTCONN
 *     The socket is associated with a connection-oriented protocol and has
 *     not been connected.
 *   ENOTSOCK
 *     The argument sockfd does not refer to a socket.
 *
 * Assumptions:
 *
 ****************************************************************************/

patacongo's avatar
patacongo committed
ssize_t recvfrom(int sockfd, FAR void *buf, size_t len, int flags,
                 FAR struct sockaddr *from, FAR socklen_t *fromlen)
{
  FAR struct socket *psock;

#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP)
#ifdef CONFIG_NET_IPv6
patacongo's avatar
patacongo committed
  FAR struct sockaddr_in6 *infrom = (struct sockaddr_in6 *)from;
#else
patacongo's avatar
patacongo committed
  FAR struct sockaddr_in *infrom = (struct sockaddr_in *)from;
#endif
  int err;

  /* Verify that non-NULL pointers were passed */

patacongo's avatar
patacongo committed
#ifdef CONFIG_DEBUG
patacongo's avatar
patacongo committed
  if (!buf)
    {
      err = EINVAL;
      goto errout;
    }
patacongo's avatar
patacongo committed
#endif

  /* Get the underlying socket structure */
  /* Verify that the sockfd corresponds to valid, allocated socket */

  psock = sockfd_socket(sockfd);
  if (!psock || psock->s_crefs <= 0)
    {
      err = EBADF;
      goto errout;
    }

patacongo's avatar
patacongo committed
  /* If a 'from' address has been provided, verify that it is large
   * enough to hold this address family.
   */
patacongo's avatar
patacongo committed
  if (from)
    {
#ifdef CONFIG_NET_IPv6
patacongo's avatar
patacongo committed
      if (*fromlen < sizeof(struct sockaddr_in6))
patacongo's avatar
patacongo committed
      if (*fromlen < sizeof(struct sockaddr_in))
patacongo's avatar
patacongo committed
          err = EINVAL;
patacongo's avatar
patacongo committed
          goto errout;
        }
    }
  /* Set the socket state to receiving */
  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV);
  /* Perform the TCP/IP or UDP recv() operation */
#if defined(CONFIG_NET_UDP) && defined(CONFIG_NET_TCP)
  if (psock->s_type == SOCK_STREAM)
      ret = tcp_recvfrom(psock, buf, len, infrom);
      ret = udp_recvfrom(psock, buf, len, infrom);
#elif defined(CONFIG_NET_TCP)
  ret = tcp_recvfrom(psock, buf, len, infrom);
#elif defined(CONFIG_NET_UDP)
  ret = udp_recvfrom(psock, buf, len, infrom);
#else
  ret = -ENOSYS;
  /* Set the socket state to idle */

  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);

  /* Handle returned errors */
      err = -ret;
      goto errout;
  /* Success return */
  return ERROR;
}

#endif /* CONFIG_NET */