Пример #1
0
int socket(int domain, int type, int protocol)
{
  FAR struct socket *psock;
  int sockfd;
  int ret;

  /* Allocate a socket descriptor */

  sockfd = sockfd_allocate(0);
  if (sockfd < 0)
    {
      set_errno(ENFILE);
      return ERROR;
    }

  /* Get the underlying socket structure */

  psock = sockfd_socket(sockfd);
  if (!psock)
    {
      set_errno(ENOSYS); /* should not happen */
      goto errout;
    }

  /* Initialize the socket structure */

  ret = psock_socket(domain, type, protocol, psock);
  if (ret < 0)
    {
      /* Error already set by psock_socket() */

      goto errout;
    }

  return sockfd;

errout:
  sockfd_release(sockfd);
  return ERROR;
}
Пример #2
0
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{
  FAR struct socket *psock = sockfd_socket(sockfd);
  FAR struct socket *pnewsock;
  FAR struct uip_conn *conn;
  struct accept_s state;
#ifdef CONFIG_NET_IPv6
  FAR struct sockaddr_in6 *inaddr = (struct sockaddr_in6 *)addr;
#else
  FAR struct sockaddr_in *inaddr = (struct sockaddr_in *)addr;
#endif
  uip_lock_t save;
  int newfd;
  int err;
  int ret;

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

  if (!psock || psock->s_crefs <= 0)
    {
      /* It is not a valid socket description.  Distinguish between the cases
       * where sockfd is a just valid and when it is a valid file descriptor used
       * in the wrong context.
       */

#if CONFIG_NFILE_DESCRIPTORS > 0
      if ((unsigned int)sockfd < CONFIG_NFILE_DESCRIPTORS)
        {
          err = ENOTSOCK;
        }
      else
#endif
        {
          err = EBADF;
        }
      goto errout;
    }

  /* We have a socket descriptor, but it is a stream? */

  if (psock->s_type != SOCK_STREAM)
    {
      err = EOPNOTSUPP;
      goto errout;
    }

  /* Is the socket listening for a connection? */

  if (!_SS_ISLISTENING(psock->s_flags))
    {
      err = EINVAL;
      goto errout;
    }

  /* Verify that a valid memory block has been provided to receive the
   * address
   */

  if (addr)
    {
#ifdef CONFIG_NET_IPv6
      if (*addrlen < sizeof(struct sockaddr_in6))
#else
      if (*addrlen < sizeof(struct sockaddr_in))
#endif
        {
          err = EBADF;
          goto errout;
        }
    }

  /* Allocate a socket descriptor for the new connection now (so that it
   * cannot fail later)
   */

  newfd = sockfd_allocate(0);
  if (newfd < 0)
    {
      err = ENFILE;
      goto errout;
    }

  pnewsock = sockfd_socket(newfd);
  if (!pnewsock)
    {
      err = ENFILE;
      goto errout_with_socket;
    }

  /* Check the backlog to see if there is a connection already pending for
   * this listener.
   */

  save = uip_lock();
  conn = (struct uip_conn *)psock->s_conn;

#ifdef CONFIG_NET_TCPBACKLOG
  state.acpt_newconn = uip_backlogremove(conn);
  if (state.acpt_newconn)
    {
      /* Yes... get the address of the connected client */

      nvdbg("Pending conn=%p\n", state.acpt_newconn);
      accept_tcpsender(state.acpt_newconn, inaddr);
    }

  /* In general, this uIP-based implementation will not support non-blocking
   * socket operations... except in a few cases:  Here for TCP accept with backlog
   * enabled.  If this socket is configured as non-blocking then return EAGAIN
   * if there is no pending connection in the backlog.
   */

  else if (_SS_ISNONBLOCK(psock->s_flags))
    {
      err = EAGAIN;
      goto errout_with_lock;
    }
  else
#endif
    {
      /* Set the socket state to accepting */

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

      /* Perform the TCP accept operation */

      /* Initialize the state structure.  This is done with interrupts
       * disabled because we don't want anything to happen until we
       * are ready.
       */

      state.acpt_addr       = inaddr;
      state.acpt_newconn    = NULL;
      state.acpt_result     = OK;
      sem_init(&state.acpt_sem, 0, 0);

      /* Set up the callback in the connection */

      conn->accept_private  = (void*)&state;
      conn->accept          = accept_interrupt;

      /* Wait for the send to complete or an error to occur:  NOTES: (1)
       * uip_lockedwait will also terminate if a signal is received, (2) interrupts
       * may be disabled!  They will be re-enabled while the task sleeps and
       * automatically re-enabled when the task restarts.
       */

      ret = uip_lockedwait(&state.acpt_sem);

      /* Make sure that no further interrupts are processed */

      conn->accept_private = NULL;
      conn->accept         = NULL;

      sem_destroy(&state. acpt_sem);

      /* Set the socket state to idle */

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

      /* Check for a errors.  Errors are signaled by negative errno values
       * for the send length.
       */

      if (state.acpt_result != 0)
        {
          err = state.acpt_result;
          goto errout_with_lock;
        }

      /* If uip_lockedwait failed, then we were probably reawakened by a signal. In
       * this case, uip_lockedwait will have set errno appropriately.
       */

      if (ret < 0)
        {
          err = -ret;
          goto errout_with_lock;
        }
    }

  /* Initialize the socket structure and mark the socket as connected.
   * (The reference count on the new connection structure was set in the
   * interrupt handler).
   */

  pnewsock->s_type   = SOCK_STREAM;
  pnewsock->s_conn   = state.acpt_newconn;
  pnewsock->s_flags |= _SF_CONNECTED;
  pnewsock->s_flags &= ~_SF_CLOSED;

  /* Begin monitoring for TCP connection events on the newly connected socket */

  net_startmonitor(pnewsock);
  uip_unlock(save);
  return newfd;

errout_with_lock:
  uip_unlock(save);

errout_with_socket:
  sockfd_release(newfd);

errout:
  errno = err;
  return ERROR;
}