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

📄 ftp.c

📁 一个很有名的浏览器
💻 C
📖 第 1 页 / 共 3 页
字号:
	add_to_string(&cmd, "PASS ");	if (conn->uri->passwordlen) {		struct uri *uri = conn->uri;		add_bytes_to_string(&cmd, uri->password, uri->passwordlen);	} else if (auth && auth->valid) {		if (!auth_user_matching_uri(auth, conn->uri)) {			prompt_username_pw(conn);			return;		}		add_to_string(&cmd, auth->password);	} else {		add_to_string(&cmd, get_opt_str("protocol.ftp.anon_passwd"));	}	add_crlf_to_string(&cmd);	send_cmd(conn, &cmd, (void *) ftp_pass_info, S_LOGIN);}/* Parse PASS command response. */static voidftp_pass_info(struct connection *conn, struct read_buffer *rb){	int response = get_ftp_response(conn, rb, 0, NULL);	if (response == -1) {		abort_conn_with_state(conn, S_FTP_ERROR);		return;	}	if (!response) {		read_from_socket(conn, &conn->socket, rb, ftp_pass_info);		set_connection_state(conn, S_LOGIN);		return;	}	/* RFC959 says that possible response codes for PASS are:	 * 202 Command not implemented, superfluous at this site.	 * 230 User logged in, proceed.	 * 332 Need account for login.	 * 421 Service not available, closing control connection.	 * 500 Syntax error, command unrecognized.	 * 501 Syntax error in parameters or arguments.	 * 503 Bad sequence of commands.	 * 530 Not logged in. */	if (response == 332 || response >= 500) {		/* If we didn't have a user, we tried anonymous. But it failed, so ask for a		 * user and password */		prompt_username_pw(conn);		return;	}	if (response >= 400) {		abort_conn_with_state(conn, S_FTP_UNAVAIL);		return;	}	ftp_send_retr_req(conn, S_GETH);}/* Construct PORT command. */static voidadd_portcmd_to_string(struct string *string, unsigned char *pc){	/* From RFC 959: DATA PORT (PORT)	 *	 * The argument is a HOST-PORT specification for the data port	 * to be used in data connection.  There are defaults for both	 * the user and server data ports, and under normal	 * circumstances this command and its reply are not needed.  If	 * this command is used, the argument is the concatenation of a	 * 32-bit internet host address and a 16-bit TCP port address.	 * This address information is broken into 8-bit fields and the	 * value of each field is transmitted as a decimal number (in	 * character string representation).  The fields are separated	 * by commas.  A port command would be:	 *	 *    PORT h1,h2,h3,h4,p1,p2	 *	 * where h1 is the high order 8 bits of the internet host	 * address. */	add_to_string(string, "PORT ");	add_long_to_string(string, pc[0]);	add_char_to_string(string, ',');	add_long_to_string(string, pc[1]);	add_char_to_string(string, ',');	add_long_to_string(string, pc[2]);	add_char_to_string(string, ',');	add_long_to_string(string, pc[3]);	add_char_to_string(string, ',');	add_long_to_string(string, pc[4]);	add_char_to_string(string, ',');	add_long_to_string(string, pc[5]);}#ifdef CONFIG_IPV6/* Construct EPRT command. */static voidadd_eprtcmd_to_string(struct string *string, struct sockaddr_in6 *addr){	unsigned char addr_str[INET6_ADDRSTRLEN];	inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);	/* From RFC 2428: EPRT	 *	 * The format of EPRT is:	 *	 * EPRT<space><d><net-prt><d><net-addr><d><tcp-port><d>	 *	 * <net-prt>:	 * AF Number   Protocol	 * ---------   --------	 * 1           Internet Protocol, Version 4 [Pos81a]	 * 2           Internet Protocol, Version 6 [DH96] */	add_to_string(string, "EPRT |2|");	add_to_string(string, addr_str);	add_char_to_string(string, '|');	add_long_to_string(string, ntohs(addr->sin6_port));	add_char_to_string(string, '|');}#endif/* Create passive socket and add appropriate announcing commands to str. Then * go and retrieve appropriate object from server. * Returns NULL if error. */static struct ftp_connection_info *add_file_cmd_to_str(struct connection *conn){#ifdef CONFIG_IPV6	struct sockaddr_storage data_addr;#endif	struct ftp_connection_info *c_i;	struct string command;	int data_sock;	unsigned char pc[6];	c_i = mem_calloc(1, sizeof(*c_i));	if (!c_i) {		abort_conn_with_state(conn, S_OUT_OF_MEM);		return NULL;	}	if (!init_string(&command)) {		mem_free(c_i);		abort_conn_with_state(conn, S_OUT_OF_MEM);		return NULL;	}	conn->info = c_i;#ifdef CONFIG_IPV6	memset(&data_addr, 0, sizeof(data_addr));#endif	memset(pc, 0, 6);	if (get_opt_bool("protocol.ftp.use_pasv"))		c_i->use_pasv = 1;#ifdef CONFIG_IPV6	if (get_opt_bool("protocol.ftp.use_epsv"))		c_i->use_epsv = 1;	if (!c_i->use_epsv && conn->protocol_family == 1) {		data_sock = get_pasv6_socket(conn, conn->socket.fd, &data_addr);		if (data_sock < 0)			return NULL;		conn->data_socket.fd = data_sock;	}#endif	if (!c_i->use_pasv && conn->protocol_family != 1) {		data_sock = get_pasv_socket(conn, conn->socket.fd, pc);		if (data_sock < 0)			return NULL;		conn->data_socket.fd = data_sock;	}	if (!conn->uri->data) {		INTERNAL("conn->uri->data empty");		abort_conn_with_state(conn, S_INTERNAL);		return NULL;	}	if (!conn->uri->datalen	    || conn->uri->data[conn->uri->datalen - 1] == '/') {		/* Commands to get directory listing. */		c_i->dir = 1;		c_i->pending_commands = 4;		/* ASCII */		add_to_string(&command, "TYPE A");		add_crlf_to_string(&command);#ifdef CONFIG_IPV6		if (conn->protocol_family == 1)			if (c_i->use_epsv)				add_to_string(&command, "EPSV");			else				add_eprtcmd_to_string(&command,					(struct sockaddr_in6 *) &data_addr);		else#endif			if (c_i->use_pasv)				add_to_string(&command, "PASV");			else				add_portcmd_to_string(&command, pc);		add_crlf_to_string(&command);		add_to_string(&command, "CWD ");		add_uri_to_string(&command, conn->uri, URI_PATH);		add_crlf_to_string(&command);		add_to_string(&command, "LIST");		add_crlf_to_string(&command);		conn->from = 0;	} else {		/* Commands to get a file. */		c_i->dir = 0;		c_i->pending_commands = 3;		/* BINARY */		add_to_string(&command, "TYPE I");		add_crlf_to_string(&command);#ifdef CONFIG_IPV6		if (conn->protocol_family == 1)			if (c_i->use_epsv)				add_to_string(&command, "EPSV");			else				add_eprtcmd_to_string(&command,					(struct sockaddr_in6 *) &data_addr);		else#endif			if (c_i->use_pasv)				add_to_string(&command, "PASV");			else				add_portcmd_to_string(&command, pc);		add_crlf_to_string(&command);		if (conn->from || (conn->progress.start > 0)) {			add_to_string(&command, "REST ");			add_long_to_string(&command, conn->from							? conn->from							: conn->progress.start);			add_crlf_to_string(&command);			c_i->rest_sent = 1;			c_i->pending_commands++;		}		add_to_string(&command, "RETR ");		add_uri_to_string(&command, conn->uri, URI_PATH);		add_crlf_to_string(&command);	}	c_i->opc = c_i->pending_commands;	/* 1 byte is already reserved for cmd_buffer in struct ftp_connection_info. */	c_i = mem_realloc(c_i, sizeof(*c_i) + command.length);	if (!c_i) {		done_string(&command);		abort_conn_with_state(conn, S_OUT_OF_MEM);		return NULL;	}	memcpy(c_i->cmd_buffer, command.source, command.length + 1);	done_string(&command);	conn->info = c_i;	return c_i;}static voidsend_it_line_by_line(struct connection *conn, struct string *cmd){	struct ftp_connection_info *c_i = conn->info;	unsigned char *nl = strchr(c_i->cmd_buffer, '\n');	if (!nl) {		add_to_string(cmd, c_i->cmd_buffer);		return;	}	nl++;	add_bytes_to_string(cmd, c_i->cmd_buffer, nl - c_i->cmd_buffer);	memmove(c_i->cmd_buffer, nl, strlen(nl) + 1);}/* Send commands to retrieve file or directory. */static voidftp_send_retr_req(struct connection *conn, int state){	struct string cmd;	if (!init_string(&cmd)) {		abort_conn_with_state(conn, S_OUT_OF_MEM);		return;	}	/* We don't save return value from add_file_cmd_to_str(), as it's saved	 * in conn->info as well. */	if (!conn->info && !add_file_cmd_to_str(conn)) {		done_string(&cmd);		return;	}	/* Send it line-by-line. */	send_it_line_by_line(conn, &cmd);	send_cmd(conn, &cmd, (void *) ftp_retr_file, state);}/* Parse RETR response and return file size or -1 on error. */static long intget_filesize_from_RETR(unsigned char *data, int data_len){	long int file_len;	int pos;	int pos_file_len = 0;	/* Getting file size from text response.. */	/* 150 Opening BINARY mode data connection for hello-1.0-1.1.diff.gz (16452 bytes). */	for (pos = 0; pos < data_len && data[pos] != ASCII_LF; pos++)		if (data[pos] == '(')			pos_file_len = pos;	if (!pos_file_len || pos_file_len == data_len - 1)		return -1;	pos_file_len++;	if (!isdigit(data[pos_file_len]))		return -1;	for (pos = pos_file_len; pos < data_len; pos++)		if (!isdigit(data[pos]))			goto next;	return -1;next:	for (; pos < data_len; pos++)		if (data[pos] != ' ')			break;	if (pos + 4 > data_len)		return -1;	if (strncasecmp(&data[pos], "byte", 4))		return -1;	errno = 0;	file_len = strtol(&data[pos_file_len], NULL, 10);	if (errno) return -1;	return file_len;}static intftp_data_connect(struct connection *conn, int family, struct sockaddr_storage *sa,		 int size_of_sockaddr){	int fd = socket(family, SOCK_STREAM, 0);	if (fd < 0 || set_nonblocking_fd(fd) < 0) {		abort_conn_with_state(conn, S_FTP_ERROR);		return -1;	}	set_ip_tos_throughput(fd);	conn->data_socket.fd = fd;	/* XXX: We ignore connect() errors here. */	connect(fd, (struct sockaddr *) sa, size_of_sockaddr);	return 0;}static voidftp_retr_file(struct connection *conn, struct read_buffer *rb){	struct ftp_connection_info *c_i = conn->info;	struct sockaddr_storage sa;	int response;	if (c_i->pending_commands > 1) {		response = get_ftp_response(conn, rb, 0, &sa);		if (response == -1) {			abort_conn_with_state(conn, S_FTP_ERROR);			return;		}		if (!response) {			read_from_socket(conn, &conn->socket, rb, ftp_retr_file);			set_connection_state(conn, S_GETH);			return;		}		if (response == 227) {			if (ftp_data_connect(conn, PF_INET, &sa, sizeof(struct sockaddr_in)))				return;		}#ifdef CONFIG_IPV6		if (response == 229) {			if (ftp_data_connect(conn, PF_INET6, &sa, sizeof(struct sockaddr_in6)))				return;		}#endif		c_i->pending_commands--;		/* XXX: The case values are order numbers of commands. */		switch (c_i->opc - c_i->pending_commands) {			case 1:	/* TYPE */				break;			case 2:	/* PORT */				if (response >= 400) {					abort_conn_with_state(conn, S_FTP_PORT);					return;				}				break;			case 3:	/* REST / CWD */				if (response >= 400) {					if (c_i->dir) {						abort_conn_with_state(conn,								S_FTP_NO_FILE);						return;					}					conn->from = 0;				} else if (c_i->rest_sent) {					/* Following code is related to resume					 * feature. */					if (response == 350)						conn->from = conn->progress.start;					/* Come on, don't be nervous ;-). */					if (conn->progress.start >= 0) {						/* Update to the real value						 * which we've got from						 * Content-Range. */						conn->progress.seek = conn->from;					}					conn->progress.start = conn->from;				}				break;			default:				INTERNAL("WHAT???");		}		ftp_send_retr_req(conn, S_GETH);		return;

⌨️ 快捷键说明

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