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

📄 ftpdataio.c

📁 文件传输协议linux 下vsftpd2.1.0.tar.gz
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Part of Very Secure FTPd * Licence: GPL v2 * Author: Chris Evans * ftpdataio.c * * Code to handle FTP data connections. This includes both PORT (server * connects) and PASV (client connects) modes of data transfer. This * includes sends and receives, files and directories. */#include "ftpdataio.h"#include "session.h"#include "ftpcmdio.h"#include "ftpcodes.h"#include "utility.h"#include "tunables.h"#include "defs.h"#include "str.h"#include "strlist.h"#include "sysutil.h"#include "logging.h"#include "secbuf.h"#include "sysstr.h"#include "sysdeputil.h"#include "ascii.h"#include "oneprocess.h"#include "twoprocess.h"#include "ls.h"#include "ssl.h"#include "readwrite.h"#include "privsock.h"static void init_data_sock_params(struct vsf_session* p_sess, int sock_fd);static filesize_t calc_num_send(int file_fd, filesize_t init_offset);static struct vsf_transfer_ret do_file_send_sendfile(  struct vsf_session* p_sess, int net_fd, int file_fd,  filesize_t curr_file_offset, filesize_t bytes_to_send);static struct vsf_transfer_ret do_file_send_rwloop(  struct vsf_session* p_sess, int file_fd, int is_ascii);static struct vsf_transfer_ret do_file_recv(  struct vsf_session* p_sess, int file_fd, int is_ascii);static void handle_sigalrm(void* p_private);static void start_data_alarm(struct vsf_session* p_sess);static void handle_io(int retval, int fd, void* p_private);static int transfer_dir_internal(  struct vsf_session* p_sess, int is_control, struct vsf_sysutil_dir* p_dir,  const struct mystr* p_base_dir_str, const struct mystr* p_option_str,  const struct mystr* p_filter_str, int is_verbose);static int write_dir_list(struct vsf_session* p_sess,                          struct mystr_list* p_dir_list,                          enum EVSFRWTarget target);static unsigned int get_chunk_size();intvsf_ftpdataio_dispose_transfer_fd(struct vsf_session* p_sess){  int dispose_ret = 1;  int retval;  if (p_sess->data_fd == -1)  {    bug("no data descriptor in vsf_ftpdataio_dispose_transfer_fd");  }  /* Reset the data connection alarm so it runs anew with the blocking close */  start_data_alarm(p_sess);  vsf_sysutil_uninstall_io_handler();  if (p_sess->data_use_ssl && p_sess->ssl_slave_active)  {    char result;    priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_CLOSE);    result = priv_sock_get_result(p_sess->ssl_consumer_fd);    if (result != PRIV_SOCK_RESULT_OK)    {      dispose_ret = 0;    }  }  else if (p_sess->p_data_ssl)  {    dispose_ret = ssl_data_close(p_sess);  }  /* This close() blocks because we set SO_LINGER */  retval = vsf_sysutil_close_failok(p_sess->data_fd);  if (vsf_sysutil_retval_is_error(retval))  {    /* Do it again without blocking. */    vsf_sysutil_deactivate_linger_failok(p_sess->data_fd);    (void) vsf_sysutil_close_failok(p_sess->data_fd);  }  if (tunable_data_connection_timeout > 0)  {    vsf_sysutil_clear_alarm();  }  p_sess->data_fd = -1;  return dispose_ret;}intvsf_ftpdataio_get_pasv_fd(struct vsf_session* p_sess){  int remote_fd;  struct vsf_sysutil_sockaddr* p_accept_addr = 0;  vsf_sysutil_sockaddr_alloc(&p_accept_addr);  remote_fd = vsf_sysutil_accept_timeout(p_sess->pasv_listen_fd, p_accept_addr,                                         tunable_accept_timeout);  if (vsf_sysutil_retval_is_error(remote_fd))  {    vsf_cmdio_write(p_sess, FTP_BADSENDCONN,                    "Failed to establish connection.");    vsf_sysutil_sockaddr_clear(&p_accept_addr);    return remote_fd;  }  /* SECURITY:   * Reject the connection if it wasn't from the same IP as the   * control connection.   */  if (!tunable_pasv_promiscuous)  {    if (!vsf_sysutil_sockaddr_addr_equal(p_sess->p_remote_addr, p_accept_addr))    {      vsf_cmdio_write(p_sess, FTP_BADSENDCONN, "Security: Bad IP connecting.");      vsf_sysutil_close(remote_fd);      vsf_sysutil_sockaddr_clear(&p_accept_addr);      return -1;    }  }  vsf_sysutil_sockaddr_clear(&p_accept_addr);  init_data_sock_params(p_sess, remote_fd);  return remote_fd;}intvsf_ftpdataio_get_port_fd(struct vsf_session* p_sess){  int retval;  int remote_fd;  if (tunable_connect_from_port_20)  {    if (tunable_one_process_model)    {      remote_fd = vsf_one_process_get_priv_data_sock(p_sess);    }    else    {      remote_fd = vsf_two_process_get_priv_data_sock(p_sess);    }  }  else  {    static struct vsf_sysutil_sockaddr* s_p_addr;    remote_fd = vsf_sysutil_get_ipsock(p_sess->p_local_addr);    vsf_sysutil_sockaddr_clone(&s_p_addr, p_sess->p_local_addr);    vsf_sysutil_sockaddr_set_port(s_p_addr, 0);    retval = vsf_sysutil_bind(remote_fd, s_p_addr);    if (retval != 0)    {       die("vsf_sysutil_bind");    }  }  retval = vsf_sysutil_connect_timeout(remote_fd, p_sess->p_port_sockaddr,                                       tunable_connect_timeout);  if (vsf_sysutil_retval_is_error(retval))  {    vsf_cmdio_write(p_sess, FTP_BADSENDCONN,                    "Failed to establish connection.");    vsf_sysutil_close(remote_fd);    return -1;  }  init_data_sock_params(p_sess, remote_fd);  return remote_fd;}intvsf_ftpdataio_post_mark_connect(struct vsf_session* p_sess){  int ret = 0;  if (!p_sess->data_use_ssl)  {    return 1;  }  if (!p_sess->ssl_slave_active)  {    ret = ssl_accept(p_sess, p_sess->data_fd);  }  else  {    int sock_ret;    priv_sock_send_cmd(p_sess->ssl_consumer_fd, PRIV_SOCK_DO_SSL_HANDSHAKE);    priv_sock_send_fd(p_sess->ssl_consumer_fd, p_sess->data_fd);    sock_ret = priv_sock_get_result(p_sess->ssl_consumer_fd);    if (sock_ret == PRIV_SOCK_RESULT_OK)    {      ret = 1;    }  }  if (ret != 1)  {    static struct mystr s_err_msg;    str_alloc_text(&s_err_msg, "SSL connection failed");    if (tunable_require_ssl_reuse)    {      str_append_text(&s_err_msg, "; session reuse required");    }    vsf_cmdio_write_str(p_sess, FTP_DATATLSBAD, &s_err_msg);  }  return ret;}static voidhandle_sigalrm(void* p_private){  struct vsf_session* p_sess = (struct vsf_session*) p_private;  if (!p_sess->data_progress)  {    vsf_cmdio_write_exit(p_sess, FTP_DATA_TIMEOUT,                         "Data timeout. Reconnect. Sorry.");  }  p_sess->data_progress = 0;  start_data_alarm(p_sess);}voidstart_data_alarm(struct vsf_session* p_sess){  if (tunable_data_connection_timeout > 0)  {    vsf_sysutil_install_sighandler(kVSFSysUtilSigALRM,                                   handle_sigalrm,                                   p_sess,                                   1);    vsf_sysutil_set_alarm(tunable_data_connection_timeout);  }  else if (tunable_idle_session_timeout > 0)  {    vsf_sysutil_clear_alarm();  }}static voidinit_data_sock_params(struct vsf_session* p_sess, int sock_fd){  if (p_sess->data_fd != -1)  {    bug("data descriptor still present in init_data_sock_params");  }  p_sess->data_fd = sock_fd;  p_sess->data_progress = 0;  vsf_sysutil_activate_keepalive(sock_fd);  /* And in the vague hope it might help... */  vsf_sysutil_set_iptos_throughput(sock_fd);  /* Set up lingering, so that we wait for all data to transfer, and report   * more accurate transfer rates.   */  vsf_sysutil_activate_linger(sock_fd);  /* Start the timeout monitor */  vsf_sysutil_install_io_handler(handle_io, p_sess);  start_data_alarm(p_sess);}static voidhandle_io(int retval, int fd, void* p_private){  long curr_sec;  long curr_usec;  unsigned int bw_rate;  double elapsed;  double pause_time;  double rate_ratio;  struct vsf_session* p_sess = (struct vsf_session*) p_private;  if (p_sess->data_fd != fd || vsf_sysutil_retval_is_error(retval) ||      retval == 0)  {    return;  }  /* Note that the session hasn't stalled, i.e. don't time it out */  p_sess->data_progress = 1;  /* Apply bandwidth quotas via a little pause, if necessary */  if (p_sess->bw_rate_max == 0)  {    return;  }  /* Calculate bandwidth rate */  vsf_sysutil_update_cached_time();  curr_sec = vsf_sysutil_get_cached_time_sec();  curr_usec = vsf_sysutil_get_cached_time_usec();  elapsed = (double) (curr_sec - p_sess->bw_send_start_sec);  elapsed += (double) (curr_usec - p_sess->bw_send_start_usec) /             (double) 1000000;  if (elapsed <= (double) 0)  {    elapsed = (double) 0.01;  }  bw_rate = (unsigned int) ((double) retval / elapsed);  if (bw_rate <= p_sess->bw_rate_max)  {    p_sess->bw_send_start_sec = curr_sec;    p_sess->bw_send_start_usec = curr_usec;    return;  }  /* Tut! Rate exceeded, calculate a pause to bring things back into line */  rate_ratio = (double) bw_rate / (double) p_sess->bw_rate_max;  pause_time = (rate_ratio - (double) 1) * elapsed;  vsf_sysutil_sleep(pause_time);  vsf_sysutil_update_cached_time();  p_sess->bw_send_start_sec = vsf_sysutil_get_cached_time_sec();  p_sess->bw_send_start_usec = vsf_sysutil_get_cached_time_usec();}intvsf_ftpdataio_transfer_dir(struct vsf_session* p_sess, int is_control,                           struct vsf_sysutil_dir* p_dir,                           const struct mystr* p_base_dir_str,                           const struct mystr* p_option_str,                           const struct mystr* p_filter_str,                           int is_verbose){  return transfer_dir_internal(p_sess, is_control, p_dir, p_base_dir_str,                               p_option_str, p_filter_str, is_verbose);}static inttransfer_dir_internal(struct vsf_session* p_sess, int is_control,                      struct vsf_sysutil_dir* p_dir,                      const struct mystr* p_base_dir_str,                      const struct mystr* p_option_str,                      const struct mystr* p_filter_str,                      int is_verbose){  struct mystr_list dir_list = INIT_STRLIST;  struct mystr_list subdir_list = INIT_STRLIST;  struct mystr dir_prefix_str = INIT_MYSTR;  struct mystr_list* p_subdir_list = 0;  struct str_locate_result loc_result = str_locate_char(p_option_str, 'R');  int failed = 0;  enum EVSFRWTarget target = kVSFRWData;  if (is_control)  {    target = kVSFRWControl;

⌨️ 快捷键说明

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