コード例 #1
0
ファイル: accept.c プロジェクト: 1015472/PX4NuttX
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;
}
コード例 #2
0
ファイル: recvfrom.c プロジェクト: DuinoPilot/Firmware
static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
                            FAR struct sockaddr_in *infrom )
#endif
{
  struct recvfrom_s       state;
  uip_lock_t              save;
  int                     ret;

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

  save = uip_lock();
  recvfrom_init(psock, buf, len, infrom, &state);

  /* Handle any any TCP data already buffered in a read-ahead buffer.  NOTE
   * that there may be read-ahead data to be retrieved even after the
   * socket has been disconnected.
   */

#if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
  recvfrom_readahead(&state);

  /* The default return value is the number of bytes that we just copied into
   * the user buffer.  We will return this if the socket has become disconnected
   * or if the user request was completely satisfied with data from the readahead
   * buffers.
   */
   
  ret = state.rf_recvlen;

#else
  /* Otherwise, the default return value of zero is used (only for the case
   * where len == state.rf_buflen is zero).
   */

  ret = 0;
#endif

  /* Verify that the SOCK_STREAM has been and still is connected */

  if (!_SS_ISCONNECTED(psock->s_flags))
    {
      /* Was any data transferred from the readahead buffer after we were
       * disconnected?  If so, then return the number of bytes received.  We
       * will wait to return end disconnection indications the next time that
       * recvfrom() is called.
       *
       * If no data was received (i.e.,  ret == 0  -- it will not be negative)
       * and the connection was gracefully closed by the remote peer, then return
       * success.  If rf_recvlen is zero, the caller of recvfrom() will get an
       * end-of-file indication.
       */

#if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
      if (ret <= 0 && !_SS_ISCLOSED(psock->s_flags))
#else
      if (!_SS_ISCLOSED(psock->s_flags))
#endif
        {
          /* Nothing was previously received from the readahead buffers.
           * The SOCK_STREAM must be (re-)connected in order to receive any
           * additional data.
           */

          ret = -ENOTCONN;
        }
    }

  /* In general, this uIP-based implementation will not support non-blocking
   * socket operations... except in a few cases:  Here for TCP receive with read-ahead
   * enabled.  If this socket is configured as non-blocking then return EAGAIN
   * if no data was obtained from the read-ahead buffers.
   */

  else
#if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
  if (_SS_ISNONBLOCK(psock->s_flags))
    {
      /* Return the number of bytes read from the read-ahead buffer if
       * something was received (already in 'ret'); EAGAIN if not.
       */

      if (ret <= 0)
        {
          /* Nothing was received */

          ret = -EAGAIN;
        }
    }

  /* It is okay to block if we need to.  If there is space to receive anything
   * more, then we will wait to receive the data.  Otherwise return the number
   * of bytes read from the read-ahead buffer (already in 'ret').
   */

  else
#endif

  /* We get here when we we decide that we need to setup the wait for incoming
   * TCP/IP data.  Just a few more conditions to check:
   *
   * 1) Make sure thet there is buffer space to receive additional data
   *    (state.rf_buflen > 0).  This could be zero, for example, if read-ahead
   *    buffering was enabled and we filled the user buffer with data from
   *    the read-ahead buffers.  Aand
   * 2) if read-ahead buffering is enabled (CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0)
   *    and delay logic is disabled (CONFIG_NET_TCP_RECVDELAY == 0), then we
   *    not want to wait if we already obtained some data from the read-ahead
   *    buffer.  In that case, return now with what we have (don't want for more
   *    because there may be no timeout).
   */

#if CONFIG_NET_TCP_RECVDELAY == 0 && CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
  if (state.rf_recvlen == 0 && state.rf_buflen > 0)
#else
  if (state.rf_buflen > 0)
#endif
    {
      struct uip_conn *conn = (struct uip_conn *)psock->s_conn;

      /* Set up the callback in the connection */

      state.rf_cb = uip_tcpcallbackalloc(conn);
      if (state.rf_cb)
        {
          state.rf_cb->flags   = UIP_NEWDATA|UIP_POLL|UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT;
          state.rf_cb->priv    = (void*)&state;
          state.rf_cb->event   = recvfrom_tcpinterrupt;

          /* Wait for either the receive to complete or for an error/timeout 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.rf_sem);

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

          uip_tcpcallbackfree(conn, state.rf_cb);
          ret = recvfrom_result(ret, &state);
        }
      else
        {
          ret = -EBUSY;
        }
    }

  uip_unlock(save);
  recvfrom_uninit(&state);
  return (ssize_t)ret;
}
コード例 #3
0
ファイル: net_vfcntl.c プロジェクト: justdoitding/Nuttx_PSoC4
int net_vfcntl(int sockfd, int cmd, va_list ap)
{
  FAR struct socket *psock = sockfd_socket(sockfd);
  net_lock_t flags;
  int err = 0;
  int ret = 0;

  nvdbg("sockfd=%d cmd=%d\n", sockfd, cmd);

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

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

  /* Interrupts must be disabled in order to perform operations on socket structures */

  flags = net_lock();
  switch (cmd)
    {
      case F_DUPFD:
        /* Return a new file descriptor which shall be the lowest numbered
         * available (that is, not already open) file descriptor greater than
         * or equal to the third argument, arg, taken as an integer of type
         * int. The new file descriptor shall refer to the same open file
         * description as the original file descriptor, and shall share any
         * locks.  The FD_CLOEXEC flag associated  with the new file descriptor
         * shall be cleared to keep the file open across calls to one of the
         * exec functions.
         */

        {
          ret = net_dupsd(sockfd, va_arg(ap, int));
        }
        break;

      case F_GETFD:
        /* Get the file descriptor flags defined in <fcntl.h> that are associated
         * with the file descriptor fd.  File descriptor flags are associated
         * with a single file descriptor and do not affect other file descriptors
         * that refer to the same file.
         */

      case F_SETFD:
        /* Set the file descriptor flags defined in <fcntl.h>, that are associated
         * with fd, to the third argument, arg, taken as type int. If the
         * FD_CLOEXEC flag in the third argument is 0, the file shall remain open
         * across the exec functions; otherwise, the file shall be closed upon
         * successful execution of one  of  the  exec  functions.
         */

         err = ENOSYS; /* F_GETFD and F_SETFD not implemented */
         break;

      case F_GETFL:
        /* Get the file status flags and file access modes, defined in
         * <fcntl.h>, for the file description associated with fd. The file
         * access modes can be extracted from the return value using the
         * mask O_ACCMODE, which is defined  in <fcntl.h>. File status flags
         * and file access modes are associated with the file description
         * and do not affect other file descriptors that refer to the same
         * file with different open file descriptions.
         */

        {
          /* This summarizes the behavior of all NuttX sockets */

          ret = O_RDWR | O_SYNC | O_RSYNC;

#if defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_TCP_READAHEAD) || \
    defined(CONFIG_NET_UDP_READAHEAD)
          /* Unix domain sockets may be non-blocking.  TCP/IP and UDP/IP
           * sockets may also be non-blocking if read-ahead is enabled
           */

          if ((0
#ifdef CONFIG_NET_LOCAL
              || psock->s_domain == PF_LOCAL  /* Unix domain stream or datagram */
#endif
#ifdef CONFIG_NET_TCP_READAHEAD
              || psock->s_type == SOCK_STREAM /* IP or Unix domain stream */
#endif
#ifdef CONFIG_NET_UDP_READAHEAD
              || psock->s_type == SOCK_DGRAM  /* IP or Unix domain datagram */
#endif
              ) && _SS_ISNONBLOCK(psock->s_flags))
            {
              ret |= O_NONBLOCK;
            }
#endif /* CONFIG_NET_LOCAL || CONFIG_NET_TCP_READAHEAD || CONFIG_NET_UDP_READAHEAD */
        }
        break;

      case F_SETFL:
        /* Set the file status flags, defined in <fcntl.h>, for the file description
         * associated with fd from the corresponding  bits in the third argument,
         * arg, taken as type int. Bits corresponding to the file access mode and
         * the file creation flags, as defined in <fcntl.h>, that are set in arg shall
         * be ignored. If any bits in arg other than those mentioned here are changed
         * by the application, the result is unspecified.
         */

        {
#if defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_TCP_READAHEAD) || \
    defined(CONFIG_NET_UDP_READAHEAD)
           /* Non-blocking is the only configurable option.  And it applies
            * only Unix domain sockets and to read operations on TCP/IP
            * and UDP/IP sockets when read-ahead is enabled.
            */

          int mode =  va_arg(ap, int);
#if defined(CONFIG_NET_LOCAL_STREAM) || defined(CONFIG_NET_TCP_READAHEAD)
          if (psock->s_type == SOCK_STREAM) /* IP or Unix domain stream */
            {
               if ((mode & O_NONBLOCK) != 0)
                 {
                   psock->s_flags |= _SF_NONBLOCK;
                 }
               else
                 {
                   psock->s_flags &= ~_SF_NONBLOCK;
                 }
            }
          else
#endif
#if defined(CONFIG_NET_LOCAL_DGRAM) || defined(CONFIG_NET_UDP_READAHEAD)
          if (psock->s_type == SOCK_DGRAM)  /* IP or Unix domain datagram */
            {
               if ((mode & O_NONBLOCK) != 0)
                 {
                   psock->s_flags |= _SF_NONBLOCK;
                 }
               else
                 {
                   psock->s_flags &= ~_SF_NONBLOCK;
                 }
            }
          else
#endif
#endif /* CONFIG_NET_LOCAL || CONFIG_NET_TCP_READAHEAD || CONFIG_NET_UDP_READAHEAD */
            {
              ndbg("ERROR: Non-blocking not supported for this socket\n");
            }
        }
        break;

      case F_GETOWN:
        /* If fd refers to a socket, get the process or process group ID specified
         * to receive SIGURG signals when out-of-band data is available. Positive values
         * indicate a process ID; negative values, other than -1, indicate a process group
         * ID. If fd does not refer to a socket, the results are unspecified.
         */

      case F_SETOWN:
        /* If fd refers to a socket, set the process or process group ID specified
         * to receive SIGURG signals when out-of-band data is available, using the value
         * of the third argument, arg, taken as type int. Positive values indicate a
         * process ID; negative values, other than -1, indicate a process group ID. If
         * fd does not refer to a socket, the results are unspecified.
         */

      case F_GETLK:
        /* Get the first lock which blocks the lock description pointed to by the third
         * argument, arg, taken as a pointer to type struct flock, defined in <fcntl.h>.
         * The information retrieved shall overwrite the information passed to fcntl() in
         * the structure flock. If no lock is found that would prevent this lock from being
         * created, then the structure shall be left unchanged except for the lock type
         * which shall be set to F_UNLCK.
         */

      case F_SETLK:
        /* Set or clear a file segment lock according to the lock description pointed to
         * by the third argument, arg, taken as a pointer to type struct flock, defined in
         * <fcntl.h>. F_SETLK can establish shared (or read) locks (F_RDLCK) or exclusive
         * (or write) locks (F_WRLCK), as well  as  to  remove  either  type  of  lock  (F_UNLCK).
         * F_RDLCK, F_WRLCK, and F_UNLCK are defined in <fcntl.h>. If a shared or exclusive
         * lock cannot be set, fcntl() shall return immediately with a return value of -1.
         */

      case F_SETLKW:
        /* This command shall be equivalent to F_SETLK except that if a shared or exclusive
         * lock is blocked by other locks, the thread shall wait until the request can be
         * satisfied. If a signal that is to be caught is received while fcntl() is waiting
         * for a region, fcntl() shall be interrupted. Upon return from the signal handler,
         * fcntl() shall return -1 with errno set to [EINTR], and the lock operation shall
         * not be done.
         */

         err = ENOSYS; /* F_GETOWN, F_SETOWN, F_GETLK, F_SETLK, F_SETLKW */
         break;

      default:
         err = EINVAL;
         break;
  }

  net_unlock(flags);

errout:
  if (err != 0)
    {
      set_errno(err);
      return ERROR;
    }

  return ret;
}
コード例 #4
0
ファイル: tcp_accept.c プロジェクト: dagar/NuttX
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;
}
コード例 #5
0
ファイル: local_connect.c プロジェクト: a1ien/nuttx
int psock_local_connect(FAR struct socket *psock,
                        FAR const struct sockaddr *addr)
{
  FAR struct local_conn_s *client;
  FAR struct sockaddr_un *unaddr = (FAR struct sockaddr_un *)addr;
  FAR struct local_conn_s *conn;

  DEBUGASSERT(psock && psock->s_conn);
  client = (FAR struct local_conn_s *)psock->s_conn;

  if (client->lc_state == LOCAL_STATE_ACCEPT ||
      client->lc_state == LOCAL_STATE_CONNECTED)
    {
      return -EISCONN;
    }

  /* Find the matching server connection */

  net_lock();
  for (conn = (FAR struct local_conn_s *)g_local_listeners.head;
      conn;
      conn = (FAR struct local_conn_s *)dq_next(&conn->lc_node))
    {
      /* Anything in the listener list should be a stream socket in the
       * istening state
       */

      DEBUGASSERT(conn->lc_state == LOCAL_STATE_LISTENING &&
                  conn->lc_proto == SOCK_STREAM);

      /* Handle according to the server connection type */

      switch (conn->lc_type)
        {
        case LOCAL_TYPE_UNNAMED:   /* A Unix socket that is not bound to any name */
        case LOCAL_TYPE_ABSTRACT:  /* lc_path is length zero */
          {
#warning Missing logic
            net_unlock();
            return OK;
          }
          break;

        case LOCAL_TYPE_PATHNAME:  /* lc_path holds a null terminated string */
          {
            if (strncmp(conn->lc_path, unaddr->sun_path, UNIX_PATH_MAX-1) == 0)
              {
                int ret = OK;

                /* Bind the address and protocol */

                client->lc_proto = conn->lc_proto;
                strncpy(client->lc_path, unaddr->sun_path, UNIX_PATH_MAX-1);
                client->lc_path[UNIX_PATH_MAX-1] = '\0';
                client->lc_instance_id = local_generate_instance_id();

                /* The client is now bound to an address */

                client->lc_state = LOCAL_STATE_BOUND;

                /* We have to do more for the SOCK_STREAM family */

                if (conn->lc_proto == SOCK_STREAM)
                  {
                    ret = local_stream_connect(client, conn,
                                               _SS_ISNONBLOCK(psock->s_flags));
                  }
                else
                  {
                    net_unlock();
                  }

                return ret;
              }
          }
          break;

        default:                 /* Bad, memory must be corrupted */
          DEBUGPANIC();          /* PANIC if debug on, else fall through */

        case LOCAL_TYPE_UNTYPED: /* Type is not determined until the socket is bound */
          {
            net_unlock();
            return -EINVAL;
          }
        }
    }

  net_unlock();
  return -EADDRNOTAVAIL;
}
コード例 #6
0
int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
                       FAR socklen_t *addrlen, FAR void **newconn)

{
    FAR struct local_conn_s *server;
    FAR struct local_conn_s *client;
    FAR struct local_conn_s *conn;
    int ret;

    /* Some sanity checks */

    DEBUGASSERT(psock && psock->s_conn);
    server = (FAR struct local_conn_s *)psock->s_conn;

    if (server->lc_proto != SOCK_STREAM ||
            server->lc_state != LOCAL_STATE_LISTENING ||
            server->lc_type  != LOCAL_TYPE_PATHNAME)
    {
        return -EOPNOTSUPP;
    }

    /* Loop as necessary if we have to wait for a connection */

    for (; ; )
    {
        /* Are there pending connections.  Remove the client from the
         * head of the waiting list.
         */

        client = (FAR struct local_conn_s *)
                 dq_remfirst(&server->u.server.lc_waiters);

        if (client)
        {
            /* Decrement the number of pending clients */

            DEBUGASSERT(server->u.server.lc_pending > 0);
            server->u.server.lc_pending--;

            /* Create a new connection structure for the server side of the
             * connection.
             */

            conn = local_alloc();
            if (!conn)
            {
                ndbg("ERROR:  Failed to allocate new connection structure\n");
                ret = -ENOMEM;
            }
            else
            {
                /* Initialize the new connection structure */

                conn->lc_crefs  = 1;
                conn->lc_proto  = SOCK_STREAM;
                conn->lc_type   = LOCAL_TYPE_PATHNAME;
                conn->lc_state  = LOCAL_STATE_CONNECTED;

                strncpy(conn->lc_path, client->lc_path, UNIX_PATH_MAX-1);
                conn->lc_path[UNIX_PATH_MAX-1] = '\0';
                conn->lc_instance_id = client->lc_instance_id;

                /* Open the server-side write-only FIFO.  This should not
                 * block.
                 */

                ret = local_open_server_tx(conn,
                                           _SS_ISNONBLOCK(psock->s_flags));
                if (ret < 0)
                {
                    ndbg("ERROR: Failed to open write-only FIFOs for %s: %d\n",
                         conn->lc_path, ret);
                }
            }

            /* Do we have a connection?  Is the write-side FIFO opened? */

            if (ret == OK)
            {
                DEBUGASSERT(conn->lc_outfd >= 0);

                /* Open the server-side read-only FIFO.  This should not
                 * block because the client side has already opening it
                 * for writing.
                 */

                ret = local_open_server_rx(conn,
                                           _SS_ISNONBLOCK(psock->s_flags));
                if (ret < 0)
                {
                    ndbg("ERROR: Failed to open read-only FIFOs for %s: %d\n",
                         conn->lc_path, ret);
                }
            }

            /* Do we have a connection?  Are the FIFOs opened? */

            if (ret == OK)
            {
                DEBUGASSERT(conn->lc_infd >= 0);

                /* Return the address family */

                if (addr)
                {
                    ret = local_getaddr(client, addr, addrlen);
                }
            }

            if (ret == OK)
            {
                /* Return the client connection structure */

                *newconn = (FAR void *)conn;
            }

            /* Signal the client with the result of the connection */

            client->u.client.lc_result = ret;
            sem_post(&client->lc_waitsem);
            return ret;
        }

        /* No.. then there should be no pending connections */

        DEBUGASSERT(server->u.server.lc_pending == 0);

        /* Was the socket opened non-blocking? */

        if (_SS_ISNONBLOCK(psock->s_flags))
        {
            /* Yes.. return EAGAIN */

            return -EAGAIN;
        }

        /* Otherwise, listen for a connection and try again. */

        ret = local_waitlisten(server);
        if (ret < 0)
        {
            return ret;
        }
    }
}
コード例 #7
0
ファイル: local_sendto.c プロジェクト: chfik/terrarium_2015
ssize_t psock_local_sendto(FAR struct socket *psock, FAR const void *buf,
                           size_t len, int flags, FAR const struct sockaddr *to,
                           socklen_t tolen)
{
  FAR struct local_conn_s *conn = (FAR struct local_conn_s *)psock->s_conn;
  FAR struct sockaddr_un *unaddr = (FAR struct sockaddr_un *)to;
  ssize_t nsent;
  int ret;

  /* We keep packet sizes in a uint16_t, so there is a upper limit to the
   * 'len' that can be supported.
   */

  DEBUGASSERT(buf && len <= UINT16_MAX);

  /* Verify that this is not a connected peer socket.  It need not be
   * bound, however.  If unbound, recvfrom will see this as a nameless
   * connection.
   */

  if (conn->lc_state != LOCAL_STATE_UNBOUND &&
      conn->lc_state != LOCAL_STATE_BOUND)
    {
      /* Either not bound to address or it is connected */

      ndbg("ERROR: Connected state\n");
      return -EISCONN;
    }

  /* The outgoing FIFO should not be open */

  DEBUGASSERT(conn->lc_outfd < 0);

  /* At present, only standard pathname type address are support */

  if (tolen < sizeof(sa_family_t) + 2)
    {
     /* EFAULT - An invalid user space address was specified for a parameter */

     return -EFAULT;
    }

  /* Make sure that half duplex FIFO has been created.
   * REVISIT:  Or should be just make sure that it already exists?
   */

  ret = local_create_halfduplex(conn, unaddr->sun_path);
  if (ret < 0)
    {
      ndbg("ERROR: Failed to create FIFO for %s: %d\n",
           conn->lc_path, ret);
      return ret;
    }

  /* Open the sending side of the transfer */

  ret = local_open_sender(conn, unaddr->sun_path,
                          _SS_ISNONBLOCK(psock->s_flags));
  if (ret < 0)
    {
      ndbg("ERROR: Failed to open FIFO for %s: %d\n",
           unaddr->sun_path, ret);

      nsent = ret;
      goto errout_with_halfduplex;
    }

  /* Send the packet */

  nsent = local_send_packet(conn->lc_outfd, buf, len);
  if (nsent < 0)
    {
      ndbg("ERROR: Failed to send the packet: %d\n", ret);
    }
  else
    {
      /* local_send_packet returns 0 if all 'len' bytes were sent */

      nsent = len;
    }

  /* Now we can close the write-only socket descriptor */

  close(conn->lc_outfd);
  conn->lc_outfd = -1;

errout_with_halfduplex:
  /* Release our reference to the half duplex FIFO*/

  (void)local_release_halfduplex(conn);
  return nsent;
}
コード例 #8
0
ファイル: tcp_accept.c プロジェクト: justdoitding/Nuttx_PSoC4
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;
}