Ejemplo n.º 1
0
int bluetooth_input(FAR struct radio_driver_s *radio,
                     FAR struct iob_s *framelist,
                     FAR struct bluetooth_frame_meta_s *meta)
{
  FAR struct bluetooth_conn_s *conn;
  FAR struct iob_s *frame;
  FAR struct iob_s *next;
  int ret = OK;

  /* Check if there is a connection that will accept this packet */

  conn = bluetooth_conn_active(meta);
  if (conn != NULL)
    {
      /* Setup for the application callback (NOTE:  These should not be
       * used by PF_BLUETOOTH sockets).
       */

      radio->r_dev.d_appdata = radio->r_dev.d_buf;
      radio->r_dev.d_len     = 0;
      radio->r_dev.d_sndlen  = 0;

      /* The framelist probably contains only a single frame, but we will
       * process it as a list of frames.
       */

      for (frame = framelist; frame != NULL; frame = next)
        {
          /* Remove the frame from the list */

          next            = frame->io_flink;
          frame->io_flink = NULL;

          /* Add the frame to the RX queue */

          ret = bluetooth_queue_frame(conn, frame, meta);
          if (ret < 0)
            {
              nerr("ERROR: Failed to queue frame: %d\n", ret);
              iob_free(frame);
            }
        }

      /* Perform the application callback.  The frame may be processed now
       * if there is a user wait for an incoming frame.  Or it may pend in
       * the RX queue until some user process reads the frame.  NOTE:  The
       * return value from bluetooth_callback would distinguish these
       * cases:  BLUETOOTH_NEWDATA will still be processed if the frame
       * was not consumed.
       */

      (void)bluetooth_callback(radio, conn, BLUETOOTH_NEWDATA);
    }
  else
    {
      nwarn("WARNING: No listener\n");
    }

  return ret;
}
Ejemplo n.º 2
0
int ftpc_chmod(SESSION handle, FAR const char *path, FAR const char *mode)
{
  FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;

  /* Does the server support the size CHMOD command? */

  if (FTPC_HAS_CHMOD(session))
    {
      (void)ftpc_cmd(session, "SITE CHMOD %s %s", path, mode);

      /* Check for "502 Command not implemented" */

      if (session->code == 502)
        {
          /* No.. the server does not support the SITE CHMOD command */

          FTPC_CLR_CHMOD(session);
        }

      return OK;
    }
  else
    {
      nwarn("WARNING: Server does not support SITE CHMOD\n");
    }

  return ERROR;
}
Ejemplo n.º 3
0
static int netdev_pktradio_ioctl(FAR struct socket *psock, int cmd,
                                 unsigned long arg)
{
  FAR struct net_driver_s *dev;
  FAR char *ifname;
  int ret = -ENOTTY;

  if (arg != 0ul)
    {
      if (WL_ISPKTRADIOCMD(cmd))
        {
          /* Get the packet radio device to receive the radio IOCTL
           * command
           */

          FAR struct pktradio_ifreq_s *cmddata =
            (FAR struct pktradio_ifreq_s *)((uintptr_t)arg);

          ifname = cmddata->pifr_name;
        }
      else
        {
          /* Not a packet radio IOCTL command */

          nwarn("WARNING: Not a packet radio IOCTL command: %d\n", cmd);
          return -ENOTTY;
        }

      /* Find the device with this name */

      dev = netdev_findbyname(ifname);
      if (dev != NULL && dev->d_lltype == NET_LL_PKTRADIO)
        {
          /* Perform the device IOCTL */

          ret = dev->d_ioctl(dev, cmd, arg);
        }
    }

  return ret;
}
Ejemplo n.º 4
0
static int tcpecho_server(void)
{
  int i, maxi, listenfd, connfd, sockfd;
  int nready;
  int ret;
  ssize_t n;
  char buf[TCPECHO_MAXLINE];
  socklen_t clilen;
  bool stop = false;
  struct pollfd client[CONFIG_EXAMPLES_TCPECHO_NCONN];
  struct sockaddr_in cliaddr, servaddr;

  listenfd = socket(AF_INET, SOCK_STREAM, 0);

  if (listenfd < 0)
    {
      perror("ERROR: failed to create socket.\n");
      return ERROR;
    }

  bzero(&servaddr, sizeof(servaddr));
  servaddr.sin_family      = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port        = htons(CONFIG_EXAMPLES_TCPECHO_PORT);

  ret = bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
  if (ret < 0)
    {
      perror("ERROR: failed to bind socket.\n");
      return ERROR;
    }

  ninfo("start listening on port: %d\n", CONFIG_EXAMPLES_TCPECHO_PORT);

  ret = listen(listenfd, CONFIG_EXAMPLES_TCPECHO_BACKLOG);
  if (ret < 0)
    {
      perror("ERROR: failed to start listening\n");
      return ERROR;
    }

  client[0].fd = listenfd;
  client[0].events = POLLRDNORM;
  for (i = 1; i < CONFIG_EXAMPLES_TCPECHO_NCONN; i++)
    {
      client[i].fd = -1;        /* -1 indicates available entry */
    }

  maxi = 0;                     /* max index into client[] array */

  while (!stop)
    {
      nready = poll(client, maxi+1, TCPECHO_POLLTIMEOUT);

      if (client[0].revents & POLLRDNORM)
        {
          /* new client connection */

          clilen = sizeof(cliaddr);
          connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen);

          ninfo("new client: %s\n", inet_ntoa(cliaddr.sin_addr));

          for (i = 1; i < CONFIG_EXAMPLES_TCPECHO_NCONN; i++)
            {
              if (client[i].fd < 0)
                {
                  client[i].fd = connfd;  /* save descriptor */
                  break;
                }
            }

          if (i == CONFIG_EXAMPLES_TCPECHO_NCONN)
            {
              perror("ERROR: too many clients");
              return ERROR;
            }

          client[i].events = POLLRDNORM;
          if (i > maxi)
            {
              maxi = i;    /* max index in client[] array */
            }

          if (--nready <= 0)
            {
              continue;    /* no more readable descriptors */
            }
        }

      for (i = 1; i <= maxi; i++)
        {
          /* check all clients for data */

          if ((sockfd = client[i].fd) < 0)
            {
              continue;
            }

          if (client[i].revents & (POLLRDNORM | POLLERR))
            {
              if ( (n = read(sockfd, buf, TCPECHO_MAXLINE)) < 0)
                {
                  if (errno == ECONNRESET)
                    {
                      /* connection reset by client */

                      nwarn("WARNING: client[%d] aborted connection\n", i);

                      close(sockfd);
                      client[i].fd = -1;
                    }
                  else
                    {
                      perror("ERROR: readline error\n");
                      close(sockfd);
                      client[i].fd = -1;
                    }
                }
              else if (n == 0)
                {
                  /* connection closed by client */

                  nwarn("WARNING: client[%d] closed connection\n", i);

                  close(sockfd);
                  client[i].fd = -1;
                }
              else
                {
                  if (strcmp(buf, "exit\r\n") == 0)
                    {
                      nwarn("WARNING: client[%d] closed connection\n", i);
                      close(sockfd);
                      client[i].fd = -1;
                    }
                  else
                    {
                      write(sockfd, buf, n);
                    }
                }

              if (--nready <= 0)
                {
                  break;  /* no more readable descriptors */
                }
            }
        }
    }

  for (i = 0; i <= maxi; i++)
    {
      if (client[i].fd < 0)
        {
          continue;
        }

      close(client[i].fd);
    }

  return ret;
}
Ejemplo n.º 5
0
void netdriver_loop(void)
{
  FAR struct eth_hdr_s *eth;

  /* Check for new frames.  If so, then poll the network for new XMIT data */

  net_lock();
  (void)devif_poll(&g_sim_dev, sim_txpoll);
  net_unlock();

  /* netdev_read will return 0 on a timeout event and >0 on a data received event */

  g_sim_dev.d_len = netdev_read((FAR unsigned char *)g_sim_dev.d_buf,
                                CONFIG_NET_ETH_MTU);

  /* Disable preemption through to the following so that it behaves a little more
   * like an interrupt (otherwise, the following logic gets pre-empted an behaves
   * oddly.
   */

  sched_lock();
  if (g_sim_dev.d_len > 0)
    {
      /* Data received event.  Check for valid Ethernet header with destination == our
       * MAC address
       */

      eth = BUF;
      if (g_sim_dev.d_len > ETH_HDRLEN)
        {
         int is_ours;

         /* Figure out if this ethernet frame is addressed to us.  This affects
           * what we're willing to receive.   Note that in promiscuous mode, the
           * up_comparemac will always return 0.
           */

         is_ours = (up_comparemac(eth->dest, &g_sim_dev.d_mac.ether) == 0);

#ifdef CONFIG_NET_PKT
          /* When packet sockets are enabled, feed the frame into the packet
           * tap.
           */

          if (is_ours)
            {
              pkt_input(&g_sim_dev);
            }
#endif /* CONFIG_NET_PKT */

          /* We only accept IP packets of the configured type and ARP packets */

#ifdef CONFIG_NET_IPv4
          if (eth->type == HTONS(ETHTYPE_IP) && is_ours)
            {
              ninfo("IPv4 frame\n");

              /* Handle ARP on input then give the IPv4 packet to the network
               * layer
               */

              arp_ipin(&g_sim_dev);
              ipv4_input(&g_sim_dev);

              /* If the above function invocation resulted in data that
               * should be sent out on the network, the global variable
               * d_len is set to a value > 0.
               */

              if (g_sim_dev.d_len > 0)
                {
                  /* Update the Ethernet header with the correct MAC address */

#ifdef CONFIG_NET_IPv6
                  if (IFF_IS_IPv4(g_sim_dev.d_flags))
#endif
                    {
                      arp_out(&g_sim_dev);
                    }
#ifdef CONFIG_NET_IPv6
                  else
                    {
                      neighbor_out(&g_sim_dev);
                    }
#endif

                  /* And send the packet */

                  netdev_send(g_sim_dev.d_buf, g_sim_dev.d_len);
                }
            }
          else
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
          if (eth->type == HTONS(ETHTYPE_IP6) && is_ours)
            {
              ninfo("Iv6 frame\n");

              /* Give the IPv6 packet to the network layer */

              ipv6_input(&g_sim_dev);

              /* If the above function invocation resulted in data that
               * should be sent out on the network, the global variable
               * d_len is set to a value > 0.
               */

              if (g_sim_dev.d_len > 0)
               {
                  /* Update the Ethernet header with the correct MAC address */

#ifdef CONFIG_NET_IPv4
                  if (IFF_IS_IPv4(g_sim_dev.d_flags))
                    {
                      arp_out(&g_sim_dev);
                    }
                  else
#endif
#ifdef CONFIG_NET_IPv6
                    {
                      neighbor_out(&g_sim_dev);
                    }
#endif /* CONFIG_NET_IPv6 */

                  /* And send the packet */

                  netdev_send(g_sim_dev.d_buf, g_sim_dev.d_len);
                }
            }
          else
#endif/* CONFIG_NET_IPv6 */
#ifdef CONFIG_NET_ARP
          if (eth->type == htons(ETHTYPE_ARP))
            {
              arp_arpin(&g_sim_dev);

              /* If the above function invocation resulted in data that
               * should be sent out on the network, the global variable
               * d_len is set to a value > 0.
               */

              if (g_sim_dev.d_len > 0)
                {
                  netdev_send(g_sim_dev.d_buf, g_sim_dev.d_len);
                }
            }
          else
#endif
           {
             nwarn("WARNING: Unsupported Ethernet type %u\n", eth->type);
           }
        }
    }

  /* Otherwise, it must be a timeout event */

  else if (timer_expired(&g_periodic_timer))
    {
      timer_reset(&g_periodic_timer);
      devif_timer(&g_sim_dev, sim_txpoll);
    }

  sched_unlock();
}
Ejemplo n.º 6
0
static uint16_t psock_send_interrupt(FAR struct net_driver_s *dev,
                                     FAR void *pvconn, FAR void *pvpriv,
                                     uint16_t flags)
{
  FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn;
  FAR struct socket *psock = (FAR struct socket *)pvpriv;

#ifdef CONFIG_NETDEV_MULTINIC
  /* The TCP socket is connected and, hence, should be bound to a device.
   * Make sure that the polling device is the one that we are bound to.
   */

  DEBUGASSERT(conn->dev != NULL);
  if (dev != conn->dev)
    {
      return flags;
    }
#endif

  ninfo("flags: %04x\n", flags);

  /* If this packet contains an acknowledgement, then update the count of
   * acknowledged bytes.
   */

  if ((flags & TCP_ACKDATA) != 0)
    {
      FAR struct tcp_wrbuffer_s *wrb;
      FAR struct tcp_hdr_s *tcp;
      FAR sq_entry_t *entry;
      FAR sq_entry_t *next;
      uint32_t ackno;

      /* Get the offset address of the TCP header */

#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
      if (conn->domain == PF_INET)
#endif
        {
          DEBUGASSERT(IFF_IS_IPv4(dev->d_flags));
          tcp = TCPIPv4BUF;
        }
#endif /* CONFIG_NET_IPv4 */

#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
      else
#endif
        {
          DEBUGASSERT(IFF_IS_IPv6(dev->d_flags));
          tcp = TCPIPv6BUF;
        }
#endif /* CONFIG_NET_IPv6 */

      /* Get the ACK number from the TCP header */

      ackno = tcp_getsequence(tcp->ackno);
      ninfo("ACK: ackno=%u flags=%04x\n", ackno, flags);

      /* Look at every write buffer in the unacked_q.  The unacked_q
       * holds write buffers that have been entirely sent, but which
       * have not yet been ACKed.
       */

      for (entry = sq_peek(&conn->unacked_q); entry; entry = next)
        {
          uint32_t lastseq;

          /* Check of some or all of this write buffer has been ACKed. */

          next = sq_next(entry);
          wrb = (FAR struct tcp_wrbuffer_s *)entry;

          /* If the ACKed sequence number is greater than the start
           * sequence number of the write buffer, then some or all of
           * the write buffer has been ACKed.
           */

          if (ackno > WRB_SEQNO(wrb))
            {
              /* Get the sequence number at the end of the data */

              lastseq = WRB_SEQNO(wrb) + WRB_PKTLEN(wrb);
              ninfo("ACK: wrb=%p seqno=%u lastseq=%u pktlen=%u ackno=%u\n",
                    wrb, WRB_SEQNO(wrb), lastseq, WRB_PKTLEN(wrb), ackno);

              /* Has the entire buffer been ACKed? */

              if (ackno >= lastseq)
                {
                  ninfo("ACK: wrb=%p Freeing write buffer\n", wrb);

                  /* Yes... Remove the write buffer from ACK waiting queue */

                  sq_rem(entry, &conn->unacked_q);

                  /* And return the write buffer to the pool of free buffers */

                  tcp_wrbuffer_release(wrb);
                }
              else
                {
                  unsigned int trimlen;

                  /* No, then just trim the ACKed bytes from the beginning
                   * of the write buffer.  This will free up some I/O buffers
                   * that can be reused while are still sending the last
                   * buffers in the chain.
                   */

                  trimlen = ackno - WRB_SEQNO(wrb);
                  if (trimlen > WRB_SENT(wrb))
                    {
                      /* More data has been ACKed then we have sent? */

                      trimlen = WRB_SENT(wrb);
                    }

                  ninfo("ACK: wrb=%p trim %u bytes\n", wrb, trimlen);

                  WRB_TRIM(wrb, trimlen);
                  WRB_SEQNO(wrb) = ackno;
                  WRB_SENT(wrb) -= trimlen;

                  /* Set the new sequence number for what remains */

                  ninfo("ACK: wrb=%p seqno=%u pktlen=%u\n",
                          wrb, WRB_SEQNO(wrb), WRB_PKTLEN(wrb));
                }
            }
        }

      /* A special case is the head of the write_q which may be partially
       * sent and so can still have un-ACKed bytes that could get ACKed
       * before the entire write buffer has even been sent.
       */

      wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q);
      if (wrb && WRB_SENT(wrb) > 0 && ackno > WRB_SEQNO(wrb))
        {
          uint32_t nacked;

          /* Number of bytes that were ACKed */

          nacked = ackno - WRB_SEQNO(wrb);
          if (nacked > WRB_SENT(wrb))
            {
              /* More data has been ACKed then we have sent? ASSERT? */

              nacked = WRB_SENT(wrb);
            }

          ninfo("ACK: wrb=%p seqno=%u nacked=%u sent=%u ackno=%u\n",
                wrb, WRB_SEQNO(wrb), nacked, WRB_SENT(wrb), ackno);

          /* Trim the ACKed bytes from the beginning of the write buffer. */

          WRB_TRIM(wrb, nacked);
          WRB_SEQNO(wrb) = ackno;
          WRB_SENT(wrb) -= nacked;

          ninfo("ACK: wrb=%p seqno=%u pktlen=%u sent=%u\n",
                wrb, WRB_SEQNO(wrb), WRB_PKTLEN(wrb), WRB_SENT(wrb));
        }
    }

  /* Check for a loss of connection */

  else if ((flags & TCP_DISCONN_EVENTS) != 0)
    {
      ninfo("Lost connection: %04x\n", flags);

      if (psock->s_conn != NULL)
        {
          /* Report not connected */

          net_lostconnection(psock, flags);
        }

      /* Free write buffers and terminate polling */

      psock_lost_connection(psock, conn);
      return flags;
    }

   /* Check if we are being asked to retransmit data */

   else if ((flags & TCP_REXMIT) != 0)
    {
      FAR struct tcp_wrbuffer_s *wrb;
      FAR sq_entry_t *entry;

      ninfo("REXMIT: %04x\n", flags);

      /* If there is a partially sent write buffer at the head of the
       * write_q?  Has anything been sent from that write buffer?
       */

      wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q);
      ninfo("REXMIT: wrb=%p sent=%u\n", wrb, wrb ? WRB_SENT(wrb) : 0);

      if (wrb != NULL && WRB_SENT(wrb) > 0)
        {
          FAR struct tcp_wrbuffer_s *tmp;
          uint16_t sent;

          /* Yes.. Reset the number of bytes sent sent from the write buffer */

          sent = WRB_SENT(wrb);
          if (conn->unacked > sent)
            {
              conn->unacked -= sent;
            }
          else
            {
              conn->unacked = 0;
            }

          if (conn->sent > sent)
            {
              conn->sent -= sent;
            }
          else
            {
              conn->sent = 0;
            }

          WRB_SENT(wrb) = 0;
          ninfo("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n",
                wrb, WRB_SENT(wrb), conn->unacked, conn->sent);

          /* Increment the retransmit count on this write buffer. */

          if (++WRB_NRTX(wrb) >= TCP_MAXRTX)
            {
              nwarn("WARNING: Expiring wrb=%p nrtx=%u\n",
                    wrb, WRB_NRTX(wrb));

              /* The maximum retry count as been exhausted. Remove the write
               * buffer at the head of the queue.
               */

              tmp = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q);
              DEBUGASSERT(tmp == wrb);
              UNUSED(tmp);

              /* And return the write buffer to the free list */

              tcp_wrbuffer_release(wrb);

              /* NOTE expired is different from un-ACKed, it is designed to
               * represent the number of segments that have been sent,
               * retransmitted, and un-ACKed, if expired is not zero, the
               * connection will be closed.
               *
               * field expired can only be updated at TCP_ESTABLISHED state
               */

              conn->expired++;
            }
        }

      /* Move all segments that have been sent but not ACKed to the write
       * queue again note, the un-ACKed segments are put at the head of the
       * write_q so they can be resent as soon as possible.
       */

      while ((entry = sq_remlast(&conn->unacked_q)) != NULL)
        {
          wrb = (FAR struct tcp_wrbuffer_s *)entry;
          uint16_t sent;

          /* Reset the number of bytes sent sent from the write buffer */

          sent = WRB_SENT(wrb);
          if (conn->unacked > sent)
            {
              conn->unacked -= sent;
            }
          else
            {
              conn->unacked = 0;
            }

          if (conn->sent > sent)
            {
              conn->sent -= sent;
            }
          else
            {
              conn->sent = 0;
            }

          WRB_SENT(wrb) = 0;
          ninfo("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n",
                wrb, WRB_SENT(wrb), conn->unacked, conn->sent);

          /* Free any write buffers that have exceed the retry count */

          if (++WRB_NRTX(wrb) >= TCP_MAXRTX)
            {
              nwarn("WARNING: Expiring wrb=%p nrtx=%u\n",
                    wrb, WRB_NRTX(wrb));

              /* Return the write buffer to the free list */

              tcp_wrbuffer_release(wrb);

              /* NOTE expired is different from un-ACKed, it is designed to
               * represent the number of segments that have been sent,
               * retransmitted, and un-ACKed, if expired is not zero, the
               * connection will be closed.
               *
               * field expired can only be updated at TCP_ESTABLISHED state
               */

              conn->expired++;
              continue;
            }
          else
            {
              /* Insert the write buffer into the write_q (in sequence
               * number order).  The retransmission will occur below
               * when the write buffer with the lowest sequence number
               * is pulled from the write_q again.
               */

              ninfo("REXMIT: Moving wrb=%p nrtx=%u\n", wrb, WRB_NRTX(wrb));

              psock_insert_segment(wrb, &conn->write_q);
            }
        }
    }

  /* Check if the outgoing packet is available (it may have been claimed
   * by a sendto interrupt serving a different thread).
   */

  if (dev->d_sndlen > 0)
    {
      /* Another thread has beat us sending data, wait for the next poll */

      return flags;
    }

  /* We get here if (1) not all of the data has been ACKed, (2) we have been
   * asked to retransmit data, (3) the connection is still healthy, and (4)
   * the outgoing packet is available for our use.  In this case, we are
   * now free to send more data to receiver -- UNLESS the buffer contains
   * unprocessed incoming data.  In that event, we will have to wait for the
   * next polling cycle.
   */

  if ((conn->tcpstateflags & TCP_ESTABLISHED) &&
      (flags & (TCP_POLL | TCP_REXMIT)) &&
      !(sq_empty(&conn->write_q)))
    {
      /* Check if the destination IP address is in the ARP  or Neighbor
       * table.  If not, then the send won't actually make it out... it
       * will be replaced with an ARP request or Neighbor Solicitation.
       */

      if (psock_send_addrchck(conn))
        {
          FAR struct tcp_wrbuffer_s *wrb;
          uint32_t predicted_seqno;
          size_t sndlen;

          /* Peek at the head of the write queue (but don't remove anything
           * from the write queue yet).  We know from the above test that
           * the write_q is not empty.
           */

          wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q);
          DEBUGASSERT(wrb);

          /* Get the amount of data that we can send in the next packet.
           * We will send either the remaining data in the buffer I/O
           * buffer chain, or as much as will fit given the MSS and current
           * window size.
           */

          sndlen = WRB_PKTLEN(wrb) - WRB_SENT(wrb);
          if (sndlen > conn->mss)
            {
              sndlen = conn->mss;
            }

          if (sndlen > conn->winsize)
            {
              sndlen = conn->winsize;
            }

          ninfo("SEND: wrb=%p pktlen=%u sent=%u sndlen=%u\n",
                wrb, WRB_PKTLEN(wrb), WRB_SENT(wrb), sndlen);

          /* Set the sequence number for this segment.  If we are
           * retransmitting, then the sequence number will already
           * be set for this write buffer.
           */

           if (WRB_SEQNO(wrb) == (unsigned)-1)
            {
              WRB_SEQNO(wrb) = conn->isn + conn->sent;
            }

          /* The TCP stack updates sndseq on receipt of ACK *before*
           * this function is called. In that case sndseq will point
           * to the next unacknowledged byte (which might have already
           * been sent). We will overwrite the value of sndseq here
           * before the packet is sent.
           */

          tcp_setsequence(conn->sndseq, WRB_SEQNO(wrb) + WRB_SENT(wrb));

#ifdef NEED_IPDOMAIN_SUPPORT
          /* If both IPv4 and IPv6 support are enabled, then we will need to
           * select which one to use when generating the outgoing packet.
           * If only one domain is selected, then the setup is already in
           * place and we need do nothing.
           */

          send_ipselect(dev, psock);
#endif
          /* Then set-up to send that amount of data with the offset
           * corresponding to the amount of data already sent. (this
           * won't actually happen until the polling cycle completes).
           */

          devif_iob_send(dev, WRB_IOB(wrb), sndlen, WRB_SENT(wrb));

          /* Remember how much data we send out now so that we know
           * when everything has been acknowledged.  Just increment
           * the amount of data sent. This will be needed in sequence
           * number calculations.
           */

          conn->unacked += sndlen;
          conn->sent    += sndlen;

          /* Below prediction will become true, unless retransmission occurrence */

          predicted_seqno = tcp_getsequence(conn->sndseq) + sndlen;

          if ((predicted_seqno > conn->sndseq_max) ||
              (tcp_getsequence(conn->sndseq) > predicted_seqno)) /* overflow */
            {
               conn->sndseq_max = predicted_seqno;
            }

          ninfo("SEND: wrb=%p nrtx=%u unacked=%u sent=%u\n",
                wrb, WRB_NRTX(wrb), conn->unacked, conn->sent);

          /* Increment the count of bytes sent from this write buffer */

          WRB_SENT(wrb) += sndlen;

          ninfo("SEND: wrb=%p sent=%u pktlen=%u\n",
                wrb, WRB_SENT(wrb), WRB_PKTLEN(wrb));

          /* Remove the write buffer from the write queue if the
           * last of the data has been sent from the buffer.
           */

          DEBUGASSERT(WRB_SENT(wrb) <= WRB_PKTLEN(wrb));
          if (WRB_SENT(wrb) >= WRB_PKTLEN(wrb))
            {
              FAR struct tcp_wrbuffer_s *tmp;

              ninfo("SEND: wrb=%p Move to unacked_q\n", wrb);

              tmp = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q);
              DEBUGASSERT(tmp == wrb);
              UNUSED(tmp);

              /* Put the I/O buffer chain in the un-acked queue; the
               * segment is waiting for ACK again
               */

              psock_insert_segment(wrb, &conn->unacked_q);
            }

          /* Only one data can be sent by low level driver at once,
           * tell the caller stop polling the other connection.
           */

          flags &= ~TCP_POLL;
        }
    }

  /* Continue waiting */

  return flags;
}
Ejemplo n.º 7
0
int main(int argc, char *argv[])
{
	int ret;
	const char *cid;
	char cmd[CMD_SIZE];
	GError *err = NULL;
	_cleanup_free_ char *contents;
	int cpid = -1;
	int status;
	pid_t pid;
	_cleanup_close_ int mfd = -1;
	_cleanup_close_ int epfd = -1;
	char slname[BUF_SIZE];
	char buf[BUF_SIZE];
	int num_read;
	struct termios t;
	struct epoll_event ev;
	struct epoll_event evlist[MAX_EVENTS];

	if (argc < 2) {
		nexit("Run as: conmon <id>");
	}

	/* Get the container id */
	cid = argv[1];

	/*
	 * Set self as subreaper so we can wait for container process
	 * and return its exit code.
	 */
	ret = prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
	if (ret != 0) {
		pexit("Failed to set as subreaper");
	}

	/* Open the master pty */
	mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
	if (mfd < 0)
		pexit("Failed to open console master pty");

	/* Grant access to the slave pty */
	if (grantpt(mfd) == -1)
		pexit("Failed to grant access to slave pty");

	/* Unlock the slave pty */
	if (unlockpt(mfd) == -1) {             /* Unlock slave pty */
		pexit("Failed to unlock the slave pty");
	}

	/* Get the slave pty name */
	ret = ptsname_r(mfd, slname, BUF_SIZE);
	if (ret != 0) {
		pexit("Failed to get the slave pty name");
	}

	/* Create the container */
	snprintf(cmd, CMD_SIZE, "runc create %s --pid-file pidfile --console %s", cid, slname);
	ret = system(cmd);
	if (ret != 0) {
		nexit("Failed to create container");
	}

	/* Read the pid so we can wait for the process to exit */
	g_file_get_contents("pidfile", &contents, NULL, &err);
	if (err) {
		fprintf(stderr, "Failed to read pidfile: %s\n", err->message);
		g_error_free(err);
		exit(1);
	}

	cpid = atoi(contents);
	printf("container PID: %d\n", cpid);

	/* Save exiting termios settings */
	if (tcgetattr(STDIN_FILENO, &tty_orig) == -1)
		pexit("tcegetattr");

	/* Settings for raw mode */
	t.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN);
	t.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR | INPCK |
		       ISTRIP | IXON | IXOFF | IGNPAR | PARMRK);
	t.c_oflag &= ~OPOST;
	t.c_cc[VMIN] = 1;
	t.c_cc[VTIME] = 0;

	/* Set terminal to raw mode */
	if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t) == -1)
		pexit("tcsetattr");

	/* Setup terminal restore on exit */
	if (atexit(tty_restore) != 0)
		pexit("atexit");

	epfd = epoll_create(5);
	if (epfd < 0)
		pexit("epoll_create");
	ev.events = EPOLLIN;
	ev.data.fd = STDIN_FILENO;
	if (epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) < 0) {
		pexit("Failed to add stdin to epoll");
	}
	ev.data.fd = mfd;
	if (epoll_ctl(epfd, EPOLL_CTL_ADD, mfd, &ev) < 0) {
		pexit("Failed to add console master fd to epoll");
	}

	/* Copy data back and forth between STDIN and master fd */
	while (true) {
		int ready = epoll_wait(epfd, evlist, MAX_EVENTS, -1);
		for (int i = 0; i < ready; i++) {
			if (evlist[i].events & EPOLLIN) {
				if (evlist[i].data.fd == STDIN_FILENO) {
					num_read = read(STDIN_FILENO, buf, BUF_SIZE);
					if (num_read <= 0)
						goto out;

					if (write(mfd, buf, num_read) != num_read) {
						nwarn("partial/failed write (masterFd)");
						goto out;
					}
				} else if (evlist[i].data.fd == mfd) {
					num_read = read(mfd, buf, BUF_SIZE);
					if (num_read <= 0)
						goto out;

					if (write(STDOUT_FILENO, buf, num_read) != num_read) {
						nwarn("partial/failed write (STDOUT_FILENO)");
						goto out;
					}
				}
			} else if (evlist[i].events & (EPOLLHUP | EPOLLERR)) {
				printf("closing fd %d\n", evlist[i].data.fd);
				if (close(evlist[i].data.fd) < 0)
					pexit("close");
				goto out;
			}
		}
	}
out:
	tty_restore();

	/* Wait for the container process and record its exit code */
	while ((pid = waitpid(-1, &status, 0)) > 0) {
		printf("PID %d exited\n", pid);
		if (pid == cpid) {
			_cleanup_free_ char *status_str = NULL;
			ret = asprintf(&status_str, "%d", status);
			if (ret < 0) {
				pexit("Failed to allocate memory for status");
			}
			g_file_set_contents("exit", status_str, strlen(status_str), &err);
			if (err) {
				fprintf(stderr, "Failed to write %s to exit file: %s\n", status_str, err->message);
				g_error_free(err);
				exit(1);
			}
			break;
		}
	}

	return EXIT_SUCCESS;
}
Ejemplo n.º 8
0
static uint16_t sendto_interrupt(FAR struct net_driver_s *dev, FAR void *conn,
                                 FAR void *pvpriv, uint16_t flags)
{
  FAR struct sendto_s *pstate = (FAR struct sendto_s *)pvpriv;

  ninfo("flags: %04x\n", flags);
  if (pstate)
    {
      /* If the network device has gone down, then we will have terminate
       * the wait now with an error.
       */

      if ((flags & NETDEV_DOWN) != 0)
        {
          /* Terminate the transfer with an error. */

          nwarn("WARNING: Network is down\n");
          pstate->st_sndlen = -ENETUNREACH;
        }

      /* Check if the outgoing packet is available.  It may have been claimed
       * by a sendto interrupt serving a different thread -OR- if the output
       * buffer currently contains unprocessed incoming data.  In these cases
       * we will just have to wait for the next polling cycle.
       */

      else if (dev->d_sndlen > 0 || (flags & UDP_NEWDATA) != 0)
        {
          /* Another thread has beat us sending data or the buffer is busy,
           * Check for a timeout.  If not timed out, wait for the next
           * polling cycle and check again.
           */

#ifdef CONFIG_NET_SENDTO_TIMEOUT
          if (send_timeout(pstate))
            {
              /* Yes.. report the timeout */

              nwarn("WARNING: SEND timeout\n");
              pstate->st_sndlen = -ETIMEDOUT;
            }
          else
#endif /* CONFIG_NET_SENDTO_TIMEOUT */
            {
               /* No timeout.  Just wait for the next polling cycle */

               return flags;
            }
        }

      /* It looks like we are good to send the data */

      else
        {
#ifdef NEED_IPDOMAIN_SUPPORT
          /* If both IPv4 and IPv6 support are enabled, then we will need to
           * select which one to use when generating the outgoing packet.
           * If only one domain is selected, then the setup is already in
           * place and we need do nothing.
           */

          sendto_ipselect(dev, pstate);
#endif

          /* Copy the user data into d_appdata and send it */

          devif_send(dev, pstate->st_buffer, pstate->st_buflen);
          pstate->st_sndlen = pstate->st_buflen;
        }

      /* Don't allow any further call backs. */

      pstate->st_cb->flags   = 0;
      pstate->st_cb->priv    = NULL;
      pstate->st_cb->event   = NULL;

      /* Wake up the waiting thread */

      sem_post(&pstate->st_sem);
    }

  return flags;
}
Ejemplo n.º 9
0
FAR struct tcp_conn_s *tcp_alloc(uint8_t domain)
{
  FAR struct tcp_conn_s *conn;

  /* Because this routine is called from both interrupt level and
   * and from user level, we have not option but to disable interrupts
   * while accessing g_free_tcp_connections[];
   */

  net_lock();

  /* Return the entry from the head of the free list */

  conn = (FAR struct tcp_conn_s *)dq_remfirst(&g_free_tcp_connections);

#ifndef CONFIG_NET_SOLINGER
  /* Is the free list empty? */

  if (!conn)
    {
      /* As a fall-back, check for connection structures which can be stalled.
       *
       * Search the active connection list for the oldest connection
       * that is about to be closed anyway.
       */

      FAR struct tcp_conn_s *tmp =
        (FAR struct tcp_conn_s *)g_active_tcp_connections.head;

      while (tmp)
        {
          ninfo("conn: %p state: %02x\n", tmp, tmp->tcpstateflags);

          /* Is this connection in a state we can sacrifice. */

          /* REVISIT: maybe we could check for SO_LINGER but it's buried
           * in the socket layer.
           */

          if (tmp->tcpstateflags == TCP_CLOSING    ||
              tmp->tcpstateflags == TCP_FIN_WAIT_1 ||
              tmp->tcpstateflags == TCP_FIN_WAIT_2 ||
              tmp->tcpstateflags == TCP_TIME_WAIT  ||
              tmp->tcpstateflags == TCP_LAST_ACK)
            {
              /* Yes.. Is it the oldest one we have seen so far? */

              if (!conn || tmp->timer > conn->timer)
                {
                  /* Yes.. remember it */

                  conn = tmp;
                }
            }

          /* Look at the next active connection */

          tmp = (FAR struct tcp_conn_s *)tmp->node.flink;
        }

      /* Did we find a connection that we can re-use? */

      if (conn != NULL)
        {
          nwarn("WARNING: Closing unestablished connection: %p\n", conn);

          /* Yes... free it.  This will remove the connection from the list
           * of active connections and release all resources held by the
           * connection.
           *
           * REVISIT:  Could there be any higher level, socket interface
           * that needs to be informed that we did this to them?
           *
           * Actually yes. When CONFIG_NET_SOLINGER is enabled there is a
           * pending callback in netclose_disconnect waiting for getting
           * woken up.  Otherwise there's the callback too, but no one is
           * waiting for it.
           */

          tcp_free(conn);

          /* Now there is guaranteed to be one free connection.  Get it! */

          conn = (FAR struct tcp_conn_s *)dq_remfirst(&g_free_tcp_connections);
        }
    }
#endif

  net_unlock();

  /* Mark the connection allocated */

  if (conn)
    {
      memset(conn, 0, sizeof(struct tcp_conn_s));
      conn->tcpstateflags = TCP_ALLOCATED;
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
      conn->domain        = domain;
#endif
    }

  return conn;
}