Пример #1
0
static int accept_interrupt(struct uip_conn *listener, struct uip_conn *conn)
{
  struct accept_s *pstate = (struct accept_s *)listener->accept_private;
  int ret = -EINVAL;

  if (pstate)
    {
      /* Get the connection address */

      accept_tcpsender(conn, pstate->acpt_addr);

      /* Save the connection structure */

      pstate->acpt_newconn     = conn;
      pstate->acpt_result      = OK;

      /* There should be a reference of one on the new connection */

      DEBUGASSERT(conn->crefs == 1);

      /* Wake-up the waiting caller thread */

      sem_post(&pstate->acpt_sem);

      /* Stop any further callbacks */

      listener->accept_private = NULL;
      listener->accept         = NULL;
      ret                      = OK;
  }

  return ret;
}
Пример #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;
}
Пример #3
0
int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
                     FAR socklen_t *addrlen, FAR void **newconn)
{
  FAR struct tcp_conn_s *conn;
  struct accept_s state;
  int ret;

  DEBUGASSERT(psock && newconn);

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

  conn = (FAR struct tcp_conn_s *)psock->s_conn;

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

      ninfo("Pending conn=%p\n", state.acpt_newconn);
      accept_tcpsender(psock, state.acpt_newconn, addr, addrlen);
    }

  /* In general, this 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))
    {
      return -EAGAIN;
    }
  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 the network
       * locked because we don't want anything to happen until we are
       * ready.
       */

      state.acpt_sock       = psock;
      state.acpt_addr       = addr;
      state.acpt_addrlen    = addrlen;
      state.acpt_newconn    = NULL;
      state.acpt_result     = OK;

      /* This semaphore is used for signaling and, hence, should not have
       * priority inheritance enabled.
       */

      nxsem_init(&state.acpt_sem, 0, 0);
      nxsem_setprotocol(&state.acpt_sem, SEM_PRIO_NONE);

      /* Set up the callback in the connection */

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

      /* Wait for the send to complete or an error to occur:  NOTES:
       * net_lockedwait will also terminate if a signal is received.
       */

      ret = net_lockedwait(&state.acpt_sem);

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

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

      nxsem_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 signalled by negative errno values
       * for the send length.
       */

      if (state.acpt_result != 0)
        {
          DEBUGASSERT(state.acpt_result > 0);
          return -state.acpt_result;
        }

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

      if (ret < 0)
        {
          return ret;
        }
    }

  *newconn = (FAR void *)state.acpt_newconn;
  return OK;
}
Пример #4
0
int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
                     FAR socklen_t *addrlen, FAR void **newconn)
{
    FAR struct tcp_conn_s *conn;
    struct accept_s state;
    int ret;

    DEBUGASSERT(psock && newconn);

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

    conn = (FAR struct tcp_conn_s *)psock->s_conn;

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

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

    /* 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))
    {
        return -EAGAIN;
    }
    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_sock       = psock;
        state.acpt_addr       = addr;
        state.acpt_addrlen    = addrlen;
        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  = (FAR void *)&state;
        conn->accept          = accept_interrupt;

        /* Wait for the send to complete or an error to occur:  NOTES: (1)
         * net_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 = net_lockedwait(&state.acpt_sem);
        if (ret < 0)
        {
            /* The value returned by net_lockedwait() the same as the value
             * returned by sem_wait():  Zero (OK) is returned on success; -1
             * (ERROR) is returned on a failure with the errno value set
             * appropriately.
             *
             * We have to preserve the errno value here because it may be
             * altered by intervening operations.
             */

            ret = -get_errno();
            DEBUGASSERT(ret < 0);
        }

        /* 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 signalled by negative errno values
         * for the send length.
         */

        if (state.acpt_result != 0)
        {
            DEBUGASSERT(state.acpt_result > 0);
            return -state.acpt_result;
        }

        /* If net_lockedwait failed, then we were probably reawakened by a
         * signal. In this case, logic above will have set 'ret' to the
         * errno value returned by net_lockedwait().
         */

        if (ret < 0)
        {
            return ret;
        }
    }

    *newconn = (FAR void *)state.acpt_newconn;
    return OK;
}