⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpd.c

📁 picoos源码。The RTOS and the TCP/IP stack will be built automatically.
💻 C
📖 第 1 页 / 共 4 页
字号:
    if (size < 0)
    {
      if (sysGetErrno() == EWOULDBLOCK)
      {
        /* temporary disable write to the socket */
        FD_CLR(tran->sock, &globalSocketSendSet);
        tran->wrDisabled = 1;

        /* move transfer structure to the head of the list */
        if (tran != FIRST_LIST_ELEM(&transfListRoot_g, transfer_t*))
        {
          ft_listDel((lelem_t*)(void*)tran);
          ft_listAddHead(&transfListRoot_g, (lelem_t*)(void*)tran);
        }
        blockedTrans_g++;
      }
    }
    else
    if (size > 0)
    {
      if ((u16_t)size > tran->dlbufremain)
        size = (int) tran->dlbufremain;
      tran->dlbufpos += (u16_t) size;
      tran->dlbufremain -= (u16_t) size;

      tran->owner->lastTrans = COUNTERVAR;
    }
    moreToSend = 1;
  }

  return moreToSend;
}


/* This function processes all open data connections
 * and does the file up- or download for the clients that
 * are ready to send or receive data. This function handles
 * also newly set up data connections.
 */
static sint_t ft_processDataConnections(fd_set* clientset, int fdcount)
{
  transfer_t *tran, *next;
  struct sockaddr addr;
  unsigned long one = 1;
  sint_t checked;
  int   s, alen;
 
  next = FIRST_LIST_ELEM(&transfListRoot_g, transfer_t*);
  checked = 0;

  while (!END_OF_LIST(&transfListRoot_g, next) && (checked < fdcount))
  {
    tran = next;
    next = NEXT_LIST_ELEM(tran, transfer_t*);

    if ((tran->state <= TSTATE_GOTPASV) ||
        (tran->state == TSTATE_GOTPORT) ||
        !FD_ISSET(tran->sock, clientset))
    {
       continue;
    }

    checked++;
    FD_CLR(tran->sock, clientset);

    if (tran->state == TSTATE_WAITONPASV)
    {
      /* incoming PASV connection */
      alen = sizeof(addr);
      s = accept(tran->sock, (struct sockaddr*)&addr, &alen);

      ft_delSocket(tran->sock);

      if (s < 0)
      {
         ft_destroyTransfer(tran);
         continue;
      }

      tran->sock = s;
      ioctlsocket(tran->sock, FIONBIO, (void*)&one);
      ft_initTransfer(tran);

      if (tran->upload)
      {
        continue;
      }
    }

    if (tran->state < TSTATE_TRANSFER)
    {
      ft_initTransfer(tran);
      if (tran->upload)
      {
        continue;
      }
    }

    if (tran->upload)
    {
      if (ft_handleUpload(tran) != 0)
      {
        continue;
      }
    }
    else
    {
      if (ft_handleDownload(tran) != 0)
      {
        continue;
      }
    }

    /* The file transfer is done when one of the functions
     * ft_handleUpload or ft_handleDownload returned with zero.
     */
    ft_reply(tran->owner, 226, "Transfer complete.");
    tran->owner->lastTrans = COUNTERVAR;

    ft_destroyTransfer(tran);
  }

  return checked;
}


/*-------------------------------------------------------------------------*/


/* Accept and open a new connection to the next client.
 */
static void ft_acceptClient(void)
{
  struct sockaddr_in addr;
  int    s, alen;
  static sint_t errors = 0;

  alen = sizeof(addr);
  sysMemSet(&addr, 0, sizeof(addr));
  s = accept(serverSocket_g, (struct sockaddr *)&addr, &alen);

  if (s < 0)
  {
    if ((sysGetErrno() == EBADF
#ifdef EPIPE
       || sysGetErrno() == EPIPE
#endif
       ) && (++errors >= 3))
    {
      /* try to recover server socket on too much errors */
      ft_delSocket(serverSocket_g);
      serverSocket_g = ft_newServerSocket();
      errors = 0;
    }
  }
  else
  {
    errors = 0;
    if (ft_newConnection(s) != 0)
    {
      closesocket(s);
    }
  }
}


/*-------------------------------------------------------------------------*/


/* Check for timed out connections,
 * and close them.
 */
static void ft_timeout(void)
{
  connection_t *conn, *next;
  COUNTERTYPE  now = COUNTERVAR;  
  COUNTERSTYPE remain;

  /* run through the list of connections */
  next = FIRST_LIST_ELEM(&connListRoot_g, connection_t*);
  while (!END_OF_LIST(&connListRoot_g, next))
  {
    conn = next;
    next = NEXT_LIST_ELEM(conn, connection_t*);

    remain = (COUNTERSTYPE)
             (conn->lastTrans + (FTP_TIMEOUT * COUNTERTPS)) -
             (COUNTERSTYPE) now;

    if (remain <= 0)
    {
      ft_reply(conn, 421, "Timeout, closing connection.");
      ft_destroyConnection(conn);
    }
  }
}


/*-------------------------------------------------------------------------*/


/* This function removes some bytes from the
 * control connection input buffer. It is called
 * when the command line parser has finnished
 * executing a command.
 */
static void ft_removeRxbufBytes(connection_t *conn, u16_t count)
{
  sint_t i;
  if (conn->buflen <= count)
  {
    conn->buflen = 0;
  }
  else
  {
    conn->buflen -= count;
    for (i = 0; i < conn->buflen; i++)
      conn->rxbuffer[i] = conn->rxbuffer[count + i];
  }
}


/*-------------------------------------------------------------------------*/


/* create a new server socket that listens to incomming FTP requests.
 */
static int ft_newServerSocket(void)
{
  unsigned long one = 1;
  struct sockaddr_in addr;
  int s, err;
  
  s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (s < 0)
    return -1;

  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*) &one, sizeof(one));
  ioctlsocket(s, FIONBIO, (void*) &one);    /* set nonblocking mode */

  sysMemSet(&addr, 0, sizeof(addr));
  addr.sin_family      = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_port        = htons(FTP_PORT);

  err = bind(s, (struct sockaddr *)&addr, sizeof(struct sockaddr));
  if (err < 0)
  {
    if ((sysGetErrno() == ENOMEM) || (sysGetErrno() == EADDRINUSE))
    {
      /* wait some time and try again...*/
      sysSleep(500);
      err = bind(s, (struct sockaddr *)&addr, sizeof(struct sockaddr));
    }
    if (err < 0)
    {
      closesocket(s);
      sysPrintErr("Failed to bind server socket!\n");
      return -1;
    }
  }

  listen(s, 20);

  ft_addSocket(s);
  return s;
}


/*-------------------------------------------------------------------------*/


/* Initialize a data connection for sending.
 * No files and sockets are opened here, we just
 * set up the socket and initialize some values.
 * After initialization, we send the 150 reply.
 */
static void ft_initTransfer(transfer_t *tran)
{
#ifdef SO_LINGER
  struct linger ling;
#endif
#ifdef SOL_TCP
#ifdef IPTOS_THROUGHPUT
  const int mode = IPTOS_THROUGHPUT;
#endif
  unsigned long zero = 0;
#ifdef TCP_CORK
  unsigned long one = 1;
#endif
#endif

#ifdef SOL_TCP
  /* set options for maximum throughput */
#ifdef IPTOS_THROUGHPUT
    setsockopt(tran->sock, SOL_IP, IP_TOS, (void *)&mode, sizeof(mode));
#endif
    setsockopt(tran->sock, SOL_TCP, TCP_NODELAY, (void *)&zero, sizeof(zero));
#ifdef TCP_CORK
    setsockopt(tran->sock, SOL_TCP, TCP_CORK, (void *)&one, sizeof(one));
#endif
#endif

  tran->state = TSTATE_TRANSFER;

  if (tran->upload)
  {
    FD_CLR(tran->sock, &globalSocketSendSet);
    ft_addSocket(tran->sock);
  }
  else
  {
    ft_addSendSocket(tran->sock);
  }

#ifdef SO_LINGER
  ling.l_onoff = 0;
  ling.l_linger = 0;
  setsockopt(tran->sock, SOL_SOCKET, SO_LINGER, (void*)&ling, sizeof(ling));
#endif

  if (tran->dirlisting != 0)
  {
    ft_reply(tran->owner, 150,
             "Opening ASCII mode data connection for directory listing.");
  }
  else
  {
    ft_reply(tran->owner, 150, "Opening BINARY mode data connection");
  }
  if (tran->filehandle >= 0)
  {
    fsys_seek(tran->filehandle, (sint_t) tran->owner->resumePos, FSSEEK_SET);
  }
  tran->owner->lastTrans = COUNTERVAR;
}


/*-------------------------------------------------------------------------*/


/* This function tries to remove all faulty
 * file handles from the file sets.
 */
static sint_t ft_fdSanity(void)
{
  struct timeval tv = {0,0};
  connection_t   *conn, *nextc;
  transfer_t     *tran, *nextt;
  fd_set         fds;
  char           buf;

  /* Test if the server socket has failed.
     If so, destroy the socket and create a new one. */
  FD_ZERO(&fds);
  FD_SET(serverSocket_g, &fds); 
  if (select(serverSocket_g, &fds, NULL, NULL, &tv) < 0)
  {
    FD_CLR(serverSocket_g, &globalSocketSet);
    closesocket(serverSocket_g);
    serverSocket_g = ft_newServerSocket();
    if (serverSocket_g < 0)
      return -1;
  }
 
  /* close all faulty connections */
  nextc = FIRST_LIST_ELEM(&connListRoot_g, connection_t*);
  while (!END_OF_LIST(&connListRoot_g, nextc))
  {
    conn = nextc;
    nextc = NEXT_LIST_ELEM(conn, connection_t*);

    if ((recv(conn->sock, &buf, 0, 0) < 0) &&
        (sysGetErrno() == EBADF))
    {
      ft_destroyConnection(conn);
    }
  }

  /* close all faulty filetransfers */
  nextt = FIRST_LIST_ELEM(&transfListRoot_g, transfer_t*);
  while (!END_OF_LIST(&transfListRoot_g, nextt))
  {
    tran = nextt;
    nextt = NEXT_LIST_ELEM(tran, transfer_t*);

    if ((recv(tran->sock, &buf, 0, 0) < 0) &&
        (sysGetErrno() == EBADF))
    {
      ft_destroyTransfer(tran);
    }
  }

  return 0;
}


/* Returns nonzero when the ftpd is started.
 */
sint_t ftpd_running(void)
{
  return ftpd_running_g;
}


/* This function stoppes the FTP demon.
 */
sint_t ftpd_stop(void)
{
  sint_t i;
  
  if (ftpd_running_g == 0)
    return 0;

  ftpd_terminate_request_g = 1;
  for (i = 0; i < 22; i++)
  {
    sysSleep(100);
    if (ftpd_running_g == 0)
    {
      return 0;
    }
  }

  return -1; /* failed to stop FTPD */
}



/* main function. does all initialization.
 */
sint_t ftpd_start(char *username, char *password)
{
  connection_t  *conn, *nextc;
  transfer_t    *tran, *nextt;
  struct timeval timeout;
  COUNTERTYPE    wctr, bctr, bt;
  fd_set         fds, fds_send;
  sint_t          i;

  if (ftpd_running_g != 0)
    return 0;  /* we are just up and running */

  ftpd_running_g = 1;

  if ((username == NULL) || (password == NULL))
    return -1;

  sysStrncpy(username_g, username, MAX_NAMESIZE);
  sysStrncpy(password_g, password, MAX_NAMESIZE);
  username_g[MAX_NAMESIZE] = 0;
  password_g[MAX_NAMESIZE] = 0;

  ftpd_terminate_request_g = 0;
  blockedTrans_g = 0;

  FD_ZERO(&globalSocketSet);
  FD_ZERO(&globalSocketSendSet);
  open_connections_g = 0;

  serverSocket_g = ft_newServerSocket();
  if (serverSocket_g < 0)
  {
    ftpd_running_g = 0;
    return -1;
  }

  /* init lists */
  INIT_LIST_HEAD(&connListRoot_g);
  INIT_LIST_HEAD(&transfListRoot_g);

  bt = COUNTERTPS / 10;
  if (bt == 0) bt = 1;

  wctr = COUNTERVAR + 30*(COUNTERTPS);
  bctr = COUNTERVAR + bt;

  while (serverSocket_g >= 0)
  {
    /* load fds */
    fds = globalSocketSet;
    fds_send = globalSocketSendSet;

    /* wait and timeout after 1.1 second when there is no activity
     */
    timeout.tv_sec  = (blockedTrans_g == 0) ? 1 : 0;
    timeout.tv_usec = 100000;
    i = select(FD_SETSIZE, &fds, &fds_send, NULL, &timeout);

    if (ftpd_terminate_request_g != 0)
      break;

    if (i < 0)
    {
      if (sysGetErrno() == EBADF)
      {
        /* test for insane file descriptors */
        ft_fdSanity();
      }
      else
      if (sysGetErrno() != EINTR)
      {
        sysPrintErr("select() failed\n");
      }
      continue;
    }

    /* re-enable write for all temp. disabled connections */
    if (((COUNTERSTYPE)bctr - (COUNTERSTYPE)COUNTERVAR) <= 0)
    {
      bctr += bt;
      tran = FIRST_LIST_ELEM(&transfListRoot_g, transfer_t*);
      while (blockedTrans_g > 0)
      {
        if (tran->wrDisabled != 0)
        {
          ft_addSendSocket(tran->sock);
          tran->wrDisabled = 0;
        }
        tran = NEXT_LIST_ELEM(tran, transfer_t*);
        blockedTrans_g--;
      }
    }

    /* remove any timed out sockets */
    if (((COUNTERSTYPE)wctr - (COUNTERSTYPE)COUNTERVAR) <= 0)
    {
      wctr += 30*(COUNTERTPS);
      ft_timeout();
    }

    if (i > 0)
    {
      /* first handle all sends... */
      i -= ft_processDataConnections(&fds_send, i);

      /* ... then the PASV connections and uploads ... */
      i -= ft_processDataConnections(&fds, i);

      /* ... and then the rest. */
      ft_processCtrlConnections(&fds, i);

      /* check for incomming connections */
      if (FD_ISSET(serverSocket_g, &fds))
      {
        ft_acceptClient();
        if (serverSocket_g < 0)
          break;
        i--;
      }
    }
  }

  /* cleanup everything and quit then */

  /* close server socket */
  if (serverSocket_g >= 0)
    closesocket(serverSocket_g);

  /* close all connections */
  nextc = FIRST_LIST_ELEM(&connListRoot_g, connection_t*);
  while (!END_OF_LIST(&connListRoot_g, nextc))
  {
    conn = nextc;
    nextc = NEXT_LIST_ELEM(conn, connection_t*);
    if (conn->transfer != NULL)
    {
      ft_abortTransfer(conn);
    }
    ft_reply(conn, 421, "FTPD shut down.");
    ft_destroyConnection(conn);
  }

  /* close all filetransfers */
  nextt = FIRST_LIST_ELEM(&transfListRoot_g, transfer_t*);
  while (!END_OF_LIST(&transfListRoot_g, nextt))
  {
    tran = nextt;
    nextt = NEXT_LIST_ELEM(tran, transfer_t*);
    ft_destroyTransfer(tran);
  }

  ftpd_running_g = 0;
  return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -