📄 ftp-retr.c
字号:
/* Functions to help with retreiving FTP files Copyright (C) 2000 Kalum Somaratna This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#ifdef HAVE_CONFIG_H# include <config.h>#endif /* * HAVE_CONFIG_H */#include <stdio.h>#include <stdarg.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <time.h>#include <errno.h>#include <ctype.h>#include <netdb.h>#include <sys/socket.h>#include <sys/time.h>#include <netinet/in.h>#include <netinet/ip.h>#include <netinet/tcp.h>#include <signal.h>#include <setjmp.h>#include <assert.h>#include <pthread.h>#ifdef HAVE_NCURSES_H#include <ncurses.h>#else#include <curses.h>#endif /* * HAVE_CURSES */#include "connect.h"#include "resume.h"#include "ftp.h"#include "ftp-retr.h"#include "main.h"#include "mainconf.h"#include "netrc.h"#include "runtime.h"#include "misc.h"#include "debug.h"#include <fcntl.h>void clean_ftpsocks(void *cdata){ int flags; connection_data *connection = (connection_data *) cdata; debug_prz("in clean ftp sock\n"); if (connection->data_sock > 0) { flags = fcntl(connection->data_sock, F_GETFD, 0); if (flags == -1) { debug_prz("data sock invalid\n"); } else close(connection->data_sock); } if (connection->control_sock > 0) { flags = fcntl(connection->control_sock, F_GETFD, 0); if (flags == -1) { debug_prz("control sock invalid\n"); } else close(connection->control_sock); }}/* * function to get a file chunk through ftp */uerr_t ftp_get_file_chunk(connection_data * connection){ char *user, *passwd; unsigned char pasv_addr[6]; /* * for PASV */ int passive_mode = FALSE; uerr_t err; netrc_entry *netrc_ent; int tos = IPTOS_THROUGHPUT; extern pthread_mutex_t status_change_mutex; extern pthread_cond_t connecting_cond; /* * set the thread attributes */ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); /* * did we get a filename? */ assert(connection->localfile != NULL); assert(connection->file_mode != NULL); /*clear the socks */ connection->control_sock = 0; connection->data_sock = 0; /* * if there is nothing to download then return */ if (connection->status == COMPLETED) { gettimeofday(&connection->time_begin, NULL); return FTPOK; } /* Broadcast the condition here */ pthread_mutex_lock(&status_change_mutex); /* Change the connection status */ connection->status = CONNECTING; pthread_cond_broadcast(&connecting_cond); pthread_mutex_unlock(&status_change_mutex); err = ftp_connect_to_server(&(connection->control_sock), connection->u.host, connection->u.port); if (err != FTPOK) { if (err == FTPCONREFUSED) { close(connection->control_sock); connection->status = CONREJECT; /* * message("Login was not allowed by the server!"); */ return err; } else { message("Error connecting to %s", connection->u.host); connection->status = REMOTEFATAL; return err; } } message("connect ok"); user = connection->u.user; passwd = connection->u.passwd; /* * Use .netrc if asked to do so. */ if (rt.use_netrc == TRUE) { netrc_ent = search_netrc(rt.netrc_list, connection->u.host); if (netrc_ent != NULL) { user = netrc_ent->account; passwd = netrc_ent->password; } } user = user ? user : DEFAULT_FTP_USER; passwd = passwd ? passwd : DEFAULT_FTP_PASSWD; message("Logging in as user %s password %s", user, passwd); connection->status = LOGGININ; /* * if the login was refused the send FTPLOGREFUSED */ err = ftp_login(connection->control_sock, user, passwd); if (err != FTPOK) { if (err == FTPLOGREFUSED) { close(connection->control_sock); connection->status = LOGINFAIL; /* * message("Login was not allowed by the server!"); */ return err; } else { message("login failed"); close(connection->control_sock); connection->status = REMOTEFATAL; return err; } } else message("login ok"); err = ftp_binary(connection->control_sock); if (err != FTPOK) { message("binary failed"); close(connection->control_sock); connection->status = REMOTEFATAL; return err; } else message("binary ok"); /* * De we need to CWD */ if (*connection->u.dir) { err = ftp_cwd(connection->control_sock, connection->u.dir); if (err != FTPOK) { message("CWD failed to change to directory %s", connection->u.dir); close(connection->control_sock); connection->status = REMOTEFATAL; return err; } else message("CWD OK"); } else { message("CWD is not needed"); } /* * If enabled lets try PASV */ if (rt.use_pasv == TRUE) { err = ftp_pasv(connection->control_sock, pasv_addr); /* * If the error is due to the server not supporting PASV then * * set the flag and lets try PORT */ if (err == FTPNOPASV || err == FTPINVPASV) { message("Server doesn't seem to support PASV"); passive_mode = FALSE; } if (err == FTPOK) /* * server supports PASV */ { char dhost[256]; unsigned short dport; snprintf(dhost, sizeof(dhost), "%d.%d.%d.%d", pasv_addr[0], pasv_addr[1], pasv_addr[2], pasv_addr[3]); dport = (pasv_addr[4] << 8) + pasv_addr[5]; /* * message("Connecting to %s %d",dhost,dport); * *delay_ms(500); */ debug_prz("FTP PASV server =%s port=%d\n", dhost, dport); err = connect_to_server(&(connection->data_sock), dhost, dport, rt.timeout); if (err != NOCONERROR) { message ("Error while connecting, according to servers PASV info"); close(connection->control_sock); connection->status = REMOTEFATAL; return err; } /* * Everything seems to be ok */ passive_mode = TRUE; } else { message("Error while connecting to FTP server for PASV"); close(connection->control_sock); connection->status = REMOTEFATAL; return err; } } else { /* * Ok..since PASV is not to be used... */ passive_mode = FALSE; } if (passive_mode == FALSE) /* * try to use PORT instead */ { err = ftp_get_listen_socket(connection->control_sock, &(connection->listen_sock)); if (err != FTPOK) { message("listen failed"); close(connection->control_sock); connection->status = REMOTEFATAL; return err; } } err = ftp_rest(connection->control_sock, connection->remote_startpos); if (err != FTPOK) { message("REST failed"); close(connection->control_sock); connection->status = REMOTEFATAL; return err; } message("REST ok"); err = ftp_retr(connection->control_sock, connection->u.file); if (err != FTPOK) { message("RETR failed"); close(connection->control_sock); connection->status = REMOTEFATAL; return err; } message("RETR ok"); if (passive_mode == FALSE) /* * Then we have to accept the connection */ { err = accept_connection(connection->listen_sock, &(connection->data_sock)); if (err != ACCEPTOK) { close(connection->control_sock); connection->status = REMOTEFATAL; return err; } } /* * Lets get the file and store it * open the file with current mode */ if (! (connection->fp = fopen(connection->localfile, connection->file_mode))) { close(connection->control_sock); close(connection->data_sock); connection->status = LOCALFATAL; return FOPENERR; } /* * prioritize packets */ setsockopt(connection->data_sock, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(tos)); /* * Make sure all writes go directly to the file */ setvbuf(connection->fp, NULL, _IONBF, 0); connection->status = DOWNLOADING; /* * lets store the start time in the connections structure * if this is the first time we have started */ if ((connection->time_begin.tv_sec == 0) && (connection->time_begin.tv_usec == 0)) gettimeofday(&connection->time_begin, NULL); err = ftp_retr_fsize_known(connection, connection->fp); close(connection->control_sock); close(connection->data_sock); /* * no need to close the listen_sock since it is already * closed by accept connection */ return err;}/* a function that handles the FTP downloading of a complete file *//* such as when the server doesn't support the REST call */uerr_t ftp_get_file_to_end(connection_data * connection){ uerr_t err; char *user, *passwd; unsigned char pasv_addr[6]; /* * for PASV */ int passive_mode = FALSE; int tos = IPTOS_THROUGHPUT; netrc_entry *netrc_ent; extern pthread_mutex_t status_change_mutex; extern pthread_cond_t connecting_cond; /* * set the thread attributes */ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); /* * did we get a filename? */ assert(connection->localfile != NULL); assert(connection->file_mode != NULL); /*clear the socks */ connection->control_sock = 0; connection->data_sock = 0; /* * if there is nothing to download then return */ if (connection->status == COMPLETED) { gettimeofday(&connection->time_begin, NULL); return FTPOK; } /* Broadcast the condition here */ pthread_mutex_lock(&status_change_mutex); /* Change the connection status */ connection->status = CONNECTING; pthread_cond_broadcast(&connecting_cond); pthread_mutex_unlock(&status_change_mutex); err = ftp_connect_to_server(&(connection->control_sock), connection->u.host, connection->u.port); if (err != FTPOK) { if (err == FTPCONREFUSED) { close(connection->control_sock); connection->status = CONREJECT; /* * message("Login was not allowed by the server!"); */ return err; } else { message("Error connecting to %s", connection->u.host); connection->status = REMOTEFATAL; return err; } } message("connect ok"); user = connection->u.user; passwd = connection->u.passwd; /* * Use .netrc if asked to do so. */ if (rt.use_netrc == TRUE) { netrc_ent = search_netrc(rt.netrc_list, connection->u.host); if (netrc_ent != NULL) { user = netrc_ent->account; passwd = netrc_ent->password; } } user = user ? user : DEFAULT_FTP_USER; passwd = passwd ? passwd : DEFAULT_FTP_PASSWD; message("Logging in as user %s password %s", user, passwd); connection->status = LOGGININ; err = ftp_login(connection->control_sock, user, passwd); if (err != FTPOK) { if (err == FTPLOGREFUSED) { close(connection->control_sock); connection->status = LOGINFAIL; /* * message("Login was not allowed by the server!"); */ return err; } else { message("login failed"); close(connection->control_sock); connection->status = REMOTEFATAL; return err; } } else message("login ok"); err = ftp_binary(connection->control_sock); if (err != FTPOK) { message("binary failed"); close(connection->control_sock); connection->status = REMOTEFATAL; return err; } else message("binary ok"); /* De we need to CWD */ if (*connection->u.dir) { err = ftp_cwd(connection->control_sock, connection->u.dir); if (err != FTPOK) { message("CWD '%s' failed", connection->u.dir); close(connection->control_sock); connection->status = REMOTEFATAL; return err; } else message("CWD OK"); } else { message("CWD not needed"); } /* * If enabled lets try PASV */ if (rt.use_pasv == TRUE) { err = ftp_pasv(connection->control_sock, pasv_addr); /* * If the error is due to the server not supporting PASV then * set the flag and lets try PORT */ if (err == FTPNOPASV || err == FTPINVPASV) { message("Server doesn't seem to support PASV"); passive_mode = FALSE; } if (err == FTPOK) /* * server supports PASV */ { char dhost[256]; unsigned short dport; snprintf(dhost, sizeof(dhost), "%d.%d.%d.%d", pasv_addr[0], pasv_addr[1], pasv_addr[2], pasv_addr[3]); dport = (pasv_addr[4] << 8) + pasv_addr[5]; err = connect_to_server(&(connection->data_sock), dhost, dport, rt.timeout); if (err != NOCONERROR) { message("Error while connecting according to PASV"); connection->status = REMOTEFATAL; close(connection->control_sock); return err; } /* * Everything seems to be ok */ passive_mode = TRUE; } else { message("Error while connecting to FTP server for PASV"); close(connection->control_sock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -