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

📄 ftpd.c

📁 picoos源码。The RTOS and the TCP/IP stack will be built automatically.
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 *  Copyright (c) 2004, Dennis Kuschel.
 *  All rights reserved. 
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *   3. The name of the author may not be used to endorse or promote
 *      products derived from this software without specific prior written
 *      permission. 
 *
 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 *  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 *  INDIRECT,  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 *  OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/**
 * @file    ftpd.c
 * @author  Dennis Kuschel
 * @brief   FTP demon for embedded devices
 *
 * This software is from http://mycpu.mikrocontroller.net.
 * Please send questions and bug reports to dennis_k@freenet.de.
 */

#include "ftpd.h"
#include "filesys.h"



/*---------------------------------------------------------------------------
 *  DEFINES
 *-------------------------------------------------------------------------*/

#define FTP_PORT        21
#define FTP_MAXCON      10
#define FTP_TIMEOUT     600
#define MAX_BLOCKSIZE   4096
#define FTP_INPBUFSIZE  256
#define FTP_FNAMESIZE   FS_MAXFNAMELEN
#define MAX_NAMESIZE    16



/*---------------------------------------------------------------------------
 *  TYPEDEFS
 *-------------------------------------------------------------------------*/

/* forward declaration */
typedef struct connection_s  connection_t;
typedef struct transfer_s    transfer_t;

typedef void (*CMDFUNC_t)(connection_t *conn, char *param);


typedef struct {
  char       name[8];
  u16_t      arg;
  u16_t      auth;
  CMDFUNC_t  cmdfunc;
} CMDINFO_t;


/* List link header.
 * This structure is equal to the
 * head of struct connection_s and
 * struct transfer_s.
 */
typedef struct lelem_s  lelem_t;
struct lelem_s
{
  lelem_t   *prev;
  lelem_t   *next;
};


#define INIT_LIST_HEAD(head) \
  do { (head)->prev = head; (head)->next = head; } while(0)
#define END_OF_LIST(head, elem)  ((void*)(head) == (void*)(elem))
#define NEXT_LIST_ELEM(elem, type)   \
          (type)(void*)((lelem_t*)(void*)(elem))->next
#define PREV_LIST_ELEM(elem, type)   \
          (type)(void*)((lelem_t*)(void*)(elem))->prev
#define FIRST_LIST_ELEM(head, type)  NEXT_LIST_ELEM(head, type)
#define LAST_LIST_ELEM(head, type)   PREV_LIST_ELEM(head, type)


/* This structure describes a connection.
 */
struct connection_s
{
  lelem_t               list;
  transfer_t            *transfer;
  COUNTERTYPE           lastTrans;
  int                   sock;
  u16_t                 auth;
  u16_t                 buflen;
  u32_t                 resumePos;
  char                  username[(MAX_NAMESIZE+1+3)&~3];
  char                  rxbuffer[FTP_INPBUFSIZE];
  char                  renfrom[FTP_FNAMESIZE];
#if FS_SUBDIRECTORIES
  char                  curpath[FTP_FNAMESIZE];
#endif
};


/* This structure describes a file transfer.
 */
struct transfer_s
{
  lelem_t               list;
  connection_t          *owner;
  u16_t                 state;
  u16_t                 spare;
  u16_t                 append;
  u16_t                 upload;
  u32_t                 size;
  u32_t                 pos;
  u32_t                 dlbufpos;
  u32_t                 dlbufremain;
  COUNTERTYPE           starttime;
  struct sockaddr_in    sin;
  int                   sock;
  sint_t                wrDisabled;
  sint_t                filehandle;
  sint_t                dirhandle;
  sint_t                dirlisting;
  char                  dlbuf[MAX_BLOCKSIZE];
  char                  filename[FTP_FNAMESIZE];
};

/* transfer states */
#define TSTATE_NONE         0
#define TSTATE_GOTPASV      1
#define TSTATE_WAITONPASV   2
#define TSTATE_GOTPORT      3
#define TSTATE_WAITFORPORT  4
#define TSTATE_TRANSFER     5



/*---------------------------------------------------------------------------
 *  FUNCTION PROTOTYPES
 *-------------------------------------------------------------------------*/

static sint_t  ft_newServerSocket(void);
static sint_t  ft_fdSanity(void);
static void    ft_listAddTail(lelem_t *headelem, lelem_t *elem);
static void    ft_listAddHead(lelem_t *headelem, lelem_t *elem);
static void    ft_listDel(lelem_t *elem);
static sint_t  ft_processCtrlConnections(fd_set *clientset, int fdcount);
static sint_t  ft_processDataConnections(fd_set* clientset, int fdcount);
static sint_t  ft_handleUpload(transfer_t *tran);
static sint_t  ft_handleDownload(transfer_t *tran);
static void    ft_acceptClient(void);
static void    ft_timeout(void);
static void    ft_initTransfer(transfer_t *tran);
static void    ft_prepTransfer(transfer_t *tran);
static void    ft_execStore(connection_t *conn, char *param, sint_t appflag);
static void    ft_getFilename(connection_t *conn, char *param, char *dst);
static void    ft_execCommand(connection_t *conn);
static void    ft_removeRxbufBytes(connection_t *conn, u16_t count);
static void    ft_reply(connection_t *conn, u16_t num, const char *fmt, ...);
static void    ft_destroyConnection(connection_t *conn);
static void    ft_destroyTransfer(transfer_t *tran);
static sint_t  ft_addSendSocket(const int sock);
static sint_t  ft_addSocket(const int sock);
static void    ft_delSocket(const int sock);
static void    ft_abortTransfer(connection_t *conn);
static sint_t  ft_getNextDirEntry(transfer_t *tran, char *buf);
static sint_t  ft_newConnection(int socket);
static transfer_t*   ft_newTransfer(int socket, connection_t *conn);
static transfer_t*   ft_setupNewTransfer(connection_t *conn);
static void    ft_doListing(connection_t *conn, char *param,sint_t fulllist);
#if FS_SUBDIRECTORIES
static sint_t  ft_changeCurrentPath(connection_t *conn, char *path);
#endif

static void    ftcmd_abor(connection_t *conn, char *param);
static void    ftcmd_acct(connection_t *conn, char *param);
static void    ftcmd_allo(connection_t *conn, char *param);
static void    ftcmd_appe(connection_t *conn, char *param);
static void    ftcmd_cdup(connection_t *conn, char *param);
static void    ftcmd_cwd (connection_t *conn, char *param);
static void    ftcmd_dele(connection_t *conn, char *param);
static void    ftcmd_help(connection_t *conn, char *param);
static void    ftcmd_list(connection_t *conn, char *param);
static void    ftcmd_mdtm(connection_t *conn, char *param);
static void    ftcmd_mkd (connection_t *conn, char *param);
static void    ftcmd_mode(connection_t *conn, char *param);
static void    ftcmd_nlst(connection_t *conn, char *param);
static void    ftcmd_noop(connection_t *conn, char *param);
static void    ftcmd_rnfr(connection_t *conn, char *param);
static void    ftcmd_rnto(connection_t *conn, char *param);
static void    ftcmd_pass(connection_t *conn, char *param);
static void    ftcmd_pasv(connection_t *conn, char *param);
static void    ftcmd_port(connection_t *conn, char *param);
static void    ftcmd_pwd (connection_t *conn, char *param);
static void    ftcmd_quit(connection_t *conn, char *param);
static void    ftcmd_rein(connection_t *conn, char *param);
static void    ftcmd_rest(connection_t *conn, char *param);
static void    ftcmd_retr(connection_t *conn, char *param);
static void    ftcmd_rmd (connection_t *conn, char *param);
static void    ftcmd_size(connection_t *conn, char *param);
static void    ftcmd_stat(connection_t *conn, char *param);
static void    ftcmd_stor(connection_t *conn, char *param);
static void    ftcmd_stru(connection_t *conn, char *param);
static void    ftcmd_syst(connection_t *conn, char *param);
static void    ftcmd_type(connection_t *conn, char *param);
static void    ftcmd_user(connection_t *conn, char *param);



/*---------------------------------------------------------------------------
 *  GLOBAL VARIABLES
 *-------------------------------------------------------------------------*/

static lelem_t      connListRoot_g;
static lelem_t      transfListRoot_g;

static fd_set       globalSocketSet;
static fd_set       globalSocketSendSet;
static int          serverSocket_g;
static u32_t        open_connections_g;
static sint_t       blockedTrans_g;

#define UPLOADBUF_SIZE   0x4000
static char         upload_buf_g[UPLOADBUF_SIZE];

#define REPLYBUF_SIZE    0x200
static char         reply_buf_g[REPLYBUF_SIZE];

static volatile sint_t  ftpd_terminate_request_g = 0;
static volatile sint_t  ftpd_running_g = 0;

static char         parambuf_g[FTP_INPBUFSIZE];
static char         tempbuf_g[FTP_INPBUFSIZE];

#if FS_SUBDIRECTORIES
static char         fnamebuf_g[FTP_FNAMESIZE*2];
#endif

static char         username_g[(MAX_NAMESIZE+1+3)&~3];
static char         password_g[(MAX_NAMESIZE+1+3)&~3];

static const char   month_g[13][4] = { "???",
 "Jan","Feb","Mar","Apr","May","Jun",
 "Jul","Aug","Sep","Oct","Nov","Dec"
};

static const CMDINFO_t cmdtable_g[] = 
{
  { "user", 1, 0, ftcmd_user },
  { "pass", 1, 1, ftcmd_pass },
  { "retr", 1, 3, ftcmd_retr },
  { "acct", 1, 0, ftcmd_acct },
  { "port", 1, 3, ftcmd_port },
  { "pasv", 0, 3, ftcmd_pasv },
  { "pwd" , 0, 3, ftcmd_pwd  },
  { "xpwd", 0, 3, ftcmd_pwd  },
  { "cwd" , 1, 3, ftcmd_cwd  },
  { "xcwd", 1, 3, ftcmd_cwd  },
  { "cdup", 0, 3, ftcmd_cdup },
  { "rest", 1, 3, ftcmd_rest },
  { "list", 0, 3, ftcmd_list },
  { "nlst", 0, 3, ftcmd_nlst },
  { "type", 1, 3, ftcmd_type },
  { "mode", 1, 3, ftcmd_mode },
  { "stru", 1, 3, ftcmd_stru },
  { "size", 1, 3, ftcmd_size },
  { "mdtm", 1, 3, ftcmd_mdtm },
  { "abor", 0, 3, ftcmd_abor },
  { "dele", 1, 4, ftcmd_dele },
  { "rnfr", 1, 4, ftcmd_rnfr },
  { "rnto", 1, 4, ftcmd_rnto },
  { "mkd" , 1, 4, ftcmd_mkd  },
  { "xmkd", 1, 4, ftcmd_mkd  },
  { "rmd" , 1, 4, ftcmd_rmd  },
  { "xrmd", 1, 4, ftcmd_rmd  },
  { "allo", 1, 2, ftcmd_allo },
  { "stat", 0, 0, ftcmd_stat },
  { "noop", 0, 0, ftcmd_noop },
  { "syst", 0, 0, ftcmd_syst },
  { "help", 0, 0, ftcmd_help },
  { "quit", 0, 0, ftcmd_quit },
  { "rein", 0, 0, ftcmd_rein },
  { "stor", 1, 4, ftcmd_stor },
  { "appe", 1, 4, ftcmd_appe },
  { ""    , 0, 0, NULL       }
};



/*---------------------------------------------------------------------------
 *  FUNCTION IMPLEMENTATION
 *-------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------
 *  FTP COMMANDS
 *-------------------------------------------------------------------------*/

/* Handle the ABOR command.
 */
static void ftcmd_abor(connection_t *conn, char *param)
{
  (void) param;
  if (conn->transfer != NULL)
  {
    ft_abortTransfer(conn);
  }
  ft_reply(conn, 226, "ABOR successful.");
}


/* Handle the ACCT command.
 * This command is not handled by us, since we will
 * never ask the client for an account identification.
 */
static void ftcmd_acct(connection_t *conn, char *param)
{
  (void) param;
  ft_reply(conn, 202, "ACCT not supported.");
}


/* Handle the ALLO command.
 * We do not need forward allocation, so we behave
 * like a NOOP (see RFC959).
 */
static void ftcmd_allo(connection_t *conn, char *param)
{
  (void) param;
  ft_reply(conn, 200, "ALLO not necessary, OK.");
}


/* Handle the APPE command.
 * Note that the function ft_execStore() does the rest.
 */
static void ftcmd_appe(connection_t *conn, char *param)
{
  (void) param;
  ft_execStore(conn, param, 1);
}


#if FS_SUBDIRECTORIES

/* Change the current working directory.
 */
static sint_t ft_changeCurrentPath(connection_t *conn, char *path)
{
  struct fsys_stat st;
  sint_t i;
  char   c;

  if ((*path == '/') || (*path == '\\'))
  {
    i = fsys_buildPathName(fnamebuf_g, path, "");
  }
  else
  {
    sysStrcpy(fnamebuf_g, conn->curpath);
    sysStrcat(fnamebuf_g, "/");
    sysStrcat(fnamebuf_g, path);
    i = fsys_buildPathName(fnamebuf_g, fnamebuf_g, "");
  }

  if (i < 0)
    return -1;

  if (i > 0)
  {
    c = fnamebuf_g[i-1];
    if (c == '/')
      fnamebuf_g[i-1] = 0;
  }

  if (*fnamebuf_g != 0)
  {
    if (fsys_stat(fnamebuf_g, &st) < 0)
      return -1;
    if ((st.st_mode & FSS_IFDIR) == 0)
      return -1;
  }
  sysStrcpy(conn->curpath, fnamebuf_g);
  return 0;
}

#endif /* FS_SUBDIRECTORIES */


/* Handle a CDUP command.
 */
static void ftcmd_cdup(connection_t *conn, char *param)
{
  (void) param;

#if FS_SUBDIRECTORIES

  if (ft_changeCurrentPath(conn, "..") == 0)
  {
    ft_reply(conn, 250, "CDUP successful.");
  }
  else
  {
    ft_reply(conn, 550, "CDUP failed.");
  }

#else /* FS_SUBDIRECTORIES */

  /* subdirectorys are not supported */
  ft_reply(conn, 250, "CDUP successful.");

#endif
}


/* Handle CWD command.
 */
static void ftcmd_cwd(connection_t *conn, char *param)
{
#if  FS_SUBDIRECTORIES 
 
  if (ft_changeCurrentPath(conn, param) == 0)
  {
    ft_reply(conn, 250, "CWD successful.");
  }
  else
  {
    ft_reply(conn, 550, "Path not found.");
  }

#else /* FS_SUBDIRECTORIES */

  (void) param;
  ft_reply(conn, 250, "CWD successful.");

#endif /* FS_SUBDIRECTORIES */
}


/* Handle the DELE command.
 */
static void ftcmd_dele(connection_t *conn, char *param)
{
  sint_t rc = -1;

  ft_getFilename(conn, param, tempbuf_g);
  if (*tempbuf_g != 0)
  {
    rc = fsys_remove(tempbuf_g);
  }
  if (rc < 0)
  {
    ft_reply(conn, 550, "File unavailable.");
  }
  else
  {
    ft_reply(conn, 250, "File deleted.");
  }
}


/* Handle the HELP command (not supported by us).
 */
static void ftcmd_help(connection_t *conn, char *param)
{
  (void) param;
  ft_reply(conn, 214, "Sorry, no help available, "
                      "please use standard FTP commands.");
}


/* Handle the LIST command.
 */
static void ftcmd_list(connection_t *conn, char *param)
{
  ft_doListing(conn, param, 1);
}


/* Handle the MDTM command (not yet supported by us).
 */
static void ftcmd_mdtm(connection_t *conn, char *param)
{
  (void) param;
  ft_reply(conn, 502, "Command not implemented.");
}


/* Handle the MKD command.
 */
static void ftcmd_mkd(connection_t *conn, char *param)
{
#if FS_SUBDIRECTORIES

  if (fsys_buildPathName(fnamebuf_g, conn->curpath, param) >= 0)
  {
    if (fsys_mkdir(fnamebuf_g) == 0)
    {
      ft_reply(conn, 257, "\"%s\" created.", fnamebuf_g);
      return;
    }
  }
  ft_reply(conn, 550, "Failed to create directory.");

#else /* FS_SUBDIRECTORIES */

  (void) param;
  ft_reply(conn, 502, "Command not implemented.");

#endif /* FS_SUBDIRECTORIES */
}


/* Handle the MODE command.
 * (we support only the stream mode)
 */
static void ftcmd_mode(connection_t *conn, char *param)
{
  (void) param;
  if ((*param == 'S') || (*param == 's'))
  {
    ft_reply(conn, 200, "Mode is STREAM.");
  }
  else
  {
    ft_reply(conn, 504, "Unknown mode.");
  }
}


/* Handle the NLST command.
 */ 
static void ftcmd_nlst(connection_t *conn, char *param)
{
  ft_doListing(conn, param, 0);
}


/* Handle the NOOP command.
 */
static void ftcmd_noop(connection_t *conn, char *param)
{
  (void) param;
  ft_reply(conn, 200, "NOOP command successful.");
}


/* Handle the PASS command, check for password.
 */
static void ftcmd_pass(connection_t *conn, char *param)
{
  char  *pass = (char*) param;
  sint_t i;

  i = (sint_t) sysStrlen(pass);
  while ((i > 0) && (pass[i-1] == ' ')) i--;
  pass[i] = 0;

  if (conn->auth == 2)
  {
    if ((sysStrcmp(username_g, conn->username) == 0) &&
        (sysStrcmp(password_g, pass) == 0))
    {
      conn->auth = 4;
    }
    else
    {
      conn->auth = 0;

⌨️ 快捷键说明

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