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

📄 ftp.c

📁 elinks下lynx是最重要的二个文本浏览器, 在linux下非常实用, elinks也是gentoo安装过程中默认使用的浏览器, 这是elinks源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		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 socket *socket, struct read_buffer *rb){	struct connection *conn = socket->conn;	int response = get_ftp_response(conn, rb, 0, NULL);	if (response == -1) {		abort_connection(conn, S_FTP_ERROR);		return;	}	if (!response) {		read_from_socket(conn->socket, rb, S_LOGIN, ftp_pass_info);		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_connection(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/* Depending on options, get proper ftp data socket and command. * It appends ftp command (either PASV,PORT,EPSV or EPRT) to @command * string. * When PORT or EPRT are used, related sockets are created. * It returns 0 on error (data socket creation failure). */static intget_ftp_data_socket(struct connection *conn, struct string *command){	struct ftp_connection_info *ftp = conn->info;	ftp->use_pasv = get_opt_bool("protocol.ftp.use_pasv");#ifdef CONFIG_IPV6	ftp->use_epsv = get_opt_bool("protocol.ftp.use_epsv");	if (conn->socket->protocol_family == EL_PF_INET6) {		if (ftp->use_epsv) {			add_to_string(command, "EPSV");		} else {			struct sockaddr_storage data_addr;			int data_sock;			memset(&data_addr, 0, sizeof(data_addr));			data_sock = get_pasv_socket(conn->socket, &data_addr);			if (data_sock < 0) return 0;			conn->data_socket->fd = data_sock;			add_eprtcmd_to_string(command,					      (struct sockaddr_in6 *) &data_addr);		}	} else#endif	{		if (ftp->use_pasv) {			add_to_string(command, "PASV");		} else {			struct sockaddr_in sa;			unsigned char pc[6];			int data_sock;			memset(pc, 0, sizeof(pc));			data_sock = get_pasv_socket(conn->socket,			 	    (struct sockaddr_storage *) &sa);			if (data_sock < 0) return 0;			memcpy(pc, &sa.sin_addr.s_addr, 4);			memcpy(pc + 4, &sa.sin_port, 2);			conn->data_socket->fd = data_sock;			add_portcmd_to_string(command, pc);		}	}	add_crlf_to_string(command);	return 1;}/* 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){	struct ftp_connection_info *ftp;	struct string command, ftp_data_command;	if (!conn->uri->data) {		INTERNAL("conn->uri->data empty");		abort_connection(conn, S_INTERNAL);		return NULL;	}	ftp = mem_calloc(1, sizeof(*ftp));	if (!ftp) {		abort_connection(conn, S_OUT_OF_MEM);		return NULL;	}	conn->info = ftp;	/* Freed when connection is destroyed. */	if (!init_string(&command)) {		abort_connection(conn, S_OUT_OF_MEM);		return NULL;	}	if (!init_string(&ftp_data_command)) {		done_string(&command);		abort_connection(conn, S_OUT_OF_MEM);		return NULL;	}	if (!get_ftp_data_socket(conn, &ftp_data_command)) {		done_string(&command);		done_string(&ftp_data_command);		INTERNAL("Ftp data socket failure");		abort_connection(conn, S_INTERNAL);		return NULL;	}	if (!conn->uri->datalen	    || conn->uri->data[conn->uri->datalen - 1] == '/') {		/* Commands to get directory listing. */		ftp->dir = 1;		ftp->pending_commands = 4;		/* ASCII */		add_to_string(&command, "TYPE A");		add_crlf_to_string(&command);		add_string_to_string(&command, &ftp_data_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. */		ftp->dir = 0;		ftp->pending_commands = 3;		/* BINARY */		add_to_string(&command, "TYPE I");		add_crlf_to_string(&command);		add_string_to_string(&command, &ftp_data_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);			ftp->rest_sent = 1;			ftp->pending_commands++;		}		add_to_string(&command, "RETR ");		add_uri_to_string(&command, conn->uri, URI_PATH);		add_crlf_to_string(&command);	}	done_string(&ftp_data_command);	ftp->opc = ftp->pending_commands;	/* 1 byte is already reserved for cmd_buffer in struct ftp_connection_info. */	ftp = mem_realloc(ftp, sizeof(*ftp) + command.length);	if (!ftp) {		done_string(&command);		abort_connection(conn, S_OUT_OF_MEM);		return NULL;	}	memcpy(ftp->cmd_buffer, command.source, command.length + 1);	done_string(&command);	conn->info = ftp;	return ftp;}static voidsend_it_line_by_line(struct connection *conn, struct string *cmd){	struct ftp_connection_info *ftp = conn->info;	unsigned char *nl = strchr(ftp->cmd_buffer, '\n');	if (!nl) {		add_to_string(cmd, ftp->cmd_buffer);		return;	}	nl++;	add_bytes_to_string(cmd, ftp->cmd_buffer, nl - ftp->cmd_buffer);	memmove(ftp->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_connection(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 off_tget_filesize_from_RETR(unsigned char *data, int data_len){	off_t 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 = (off_t) strtol(&data[pos_file_len], NULL, 10);	if (errno) return -1;	return file_len;}static intftp_data_connect(struct connection *conn, int pf, struct sockaddr_storage *sa,		 int size_of_sockaddr){	int fd = socket(pf, SOCK_STREAM, 0);	if (fd < 0 || set_nonblocking_fd(fd) < 0) {		abort_connection(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 socket *socket, struct read_buffer *rb){	struct connection *conn = socket->conn;	struct ftp_connection_info *ftp = conn->info;	int response;	if (ftp->pending_commands > 1) {		struct sockaddr_storage sa;		response = get_ftp_response(conn, rb, 0, &sa);		if (response == -1) {			abort_connection(conn, S_FTP_ERROR);			return;		}		if (!response) {			read_from_socket(conn->socket, rb, S_GETH, ftp_retr_file);			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		ftp->pending_commands--;		/* XXX: The case values are order numbers of commands. */		switch (ftp->opc - ftp->pending_commands) {			case 1:	/* TYPE */				break;			case 2:	/* PORT */				if (response >= 400) {					abort_connection(conn, S_FTP_PORT);					return;				}				break;			case 3:	/* REST / CWD */				if (response >= 400) {					if (ftp->dir) {						abort_connection(conn,								S_FTP_NO_FILE);						return;					}					conn->from = 0;				} else if (ftp->rest_sent) {					/* Following code is related to resume

⌨️ 快捷键说明

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