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

📄 ftpd.c

📁 ftp服务器源程序
💻 C
📖 第 1 页 / 共 3 页
字号:
		}#endif		/* remove any timed out sockets */		if (time_to_check) {			time_out_sockets();#if WANT_DCACHE			time_out_dcache();#endif			time_to_check = 0;		}		if (i <= 0) continue;#if HAVE_POLL		i -= process_all_sendfiles(i);		process_all_clients(i);#else		/* sends are given highest `priority' */		i -= process_all_sendfiles(&fds_send, i);		/* incoming PASV connections and uploads */		i -= process_all_sendfiles(&fds, i);		/*		 * check the incoming PASV connections first, so		 * process_all_clients() won't be confused.		 */ 		process_all_clients(&fds, i);#endif#if HAVE_POLL		if (fds[server_sock].revents & POLLIN) {#else		if (FD_ISSET(server_sock, &fds)) {#endif			accept_new_client(&server_sock);			i--;		}	}}/* * accept_new_client(): *		Open a socket for the new client, say hello and put it in *		among the others. */void accept_new_client(int * const server_sock){	struct sockaddr_in tempaddr;	int tempaddr_len = sizeof(tempaddr);	const int tempsock = accept(*server_sock, (struct sockaddr *)&tempaddr, &tempaddr_len);	static int num_err = 0;	if (tempsock < 0) {#ifndef WANT_FORK		perror("accept()");#endif		close(tempsock);		if ((errno == EBADF || errno == EPIPE) && ++num_err >= 3) {			del_fd(*server_sock);			*server_sock = create_server_socket();		}	} else {		struct conn * const c = alloc_new_conn(tempsock);		num_err = 0;		if (c != NULL) {			numeric(c, 220, "BetaFTPD " VERSION " ready.");#if WANT_STAT			memcpy(&(c->addr), &tempaddr, sizeof(struct sockaddr));#endif		}	}}/* * time_out_sockets(): *		Times out any socket that has not had any transfer *		in the last 15 minutes (delay not customizable by FTP *		user --	you must change it in ftpd.h). * *		Note that RFC959 explicitly states that there are no *		`spontaneous' error replies, yet we have to do it to *		get the message through at all. * *		If we check this list for every accept() call, it's *		actually eating a lot of CPU time, so we only check *		it every minute. We used to do a time() call here, *		but we've changed to do use an alarm() call and set *		the time_to_check_flag in the SIGALRM handler. */RETSIGTYPE handle_alarm(int signum){	time_to_check = 1;	alarm(60);	/* for libc5 */	signal(SIGALRM, handle_alarm);}void time_out_sockets(){	struct conn *c = NULL, *next = first_conn->next_conn;	time_t now = time(NULL);  	/* run through the linked list */	while (next != NULL) {	        c = next;	        next = c->next_conn;		if ((c->transfer == NULL || c->transfer->state != 5) &&		    (now - c->last_transfer > TIMEOUT_SECS)) {			/* RFC violation? */			numeric(c, 421, "Timeout (%u minutes): Closing control connection.", TIMEOUT_SECS/60);			destroy_conn(c);		}	}}/* * remove_bytes(): *		Remove some bytes from the incoming buffer. This gives *		room for new data on the control connection, and should *		be called when the code has finished using the data. *		(This is done automatically for all commands, so you *		normally need not worry about it.) */void remove_bytes(struct conn * const c, const int num){	if (c->buf_len <= num) {		c->buf_len = 0;	} else {		c->buf_len -= num;		memmove(c->recv_buf, c->recv_buf + num, c->buf_len);	}}/* * numeric():	Sends a numeric FTP reply to the client. Note that *		you can use this command much the same way as you *		would use a printf() (with all the normal %s, %d, *		etc.), since it actually uses printf() internally. */void numeric(struct conn * const c, const int numeric, const char * const format, ...){	char buf[256], fmt[256];	va_list args;	int i, err;	snprintf(fmt, 256, "%03u %s\r\n", numeric, format);	va_start(args, format);	i = vsnprintf(buf, 256, fmt, args);	va_end(args);	err = send(c->sock, buf, i, 0);	if (err == -1 && errno == EPIPE) {		destroy_conn(c);	}}/* * init_file_transfer(): *		Initiate a data connection for sending. This does not open *		any files etc., just does whatever is needed for the socket, *		if needed. It does, however, send the 150 reply to the client, *		and mmap()s if needed. * *		Linux systems (others?) define SOL_TCP right away, which saves us *		some grief and code size. Perhaps using getprotoent() is the `right' *		way, but it's bigger :-) (Optionally, we could figure it out at *		configure time, of course...) * *		For optimal speed, we use the Linux 2.2.x-only TCP_CORK flag if *		possible. Note that this is only defined in the first `arm' -- *		we silently assume that Linux is the only OS supporting this *		flag. This might be an over-generalization, but I it looks like *		we'll have to depend on it other places as well, so we might *		just as well be evil here. */void init_file_transfer(struct ftran * const f){	struct linger ling;	struct conn * const c = f->owner;	const int mode = IPTOS_THROUGHPUT, zero = 0, one = 1;	struct stat buf;	int events;#ifdef SOL_TCP	/* we want max throughput */	setsockopt(f->sock, SOL_IP, IP_TOS, (void *)&mode, sizeof(mode));	setsockopt(f->sock, SOL_TCP, TCP_NODELAY, (void *)&zero, sizeof(zero));#ifdef TCP_CORK	setsockopt(f->sock, SOL_TCP, TCP_CORK, (void *)&one, sizeof(one));#endif#else	/* should these pointers be freed afterwards? */	{		getprotoent();	/* legal? */		{			const struct protoent * const pe_ip  = getprotobyname("ip");			const struct protoent * const pe_tcp = getprotobyname("tcp");			setsockopt(f->sock, pe_ip->p_proto, IP_TOS, (void *)&mode, sizeof(mode));			setsockopt(f->sock, pe_tcp->p_proto, TCP_NODELAY, (void *)&zero, sizeof(zero));		}		endprotoent();	}#endif	if (f->dir_listing) {		f->block_size = MAX_BLOCK_SIZE;	} else {#if WANT_ASCII		f->ascii_mode = f->owner->ascii_mode;#endif		/* find the preferred block size */		f->block_size = MAX_BLOCK_SIZE;		if (fstat(f->local_file, &buf) != -1 &&		    buf.st_blksize < MAX_BLOCK_SIZE) {			f->block_size = buf.st_blksize;		}	}	f->state = 5;	events = POLLOUT;#if WANT_UPLOAD	if (f->upload) {                events = POLLIN;        }#endif /* WANT_UPLOAD */	TRAP_ERROR(add_fd(f->sock, events), 500, return);	ling.l_onoff = 0;	ling.l_linger = 0;	setsockopt(f->sock, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));#if !HAVE_POLL && WANT_UPLOAD	/*	 * if we let an upload socket stay in master_send_fds, we would	 * get data that would fool us into closing the socket... (sigh)	 */	if (f->upload) {		FD_CLR(f->sock, &master_send_fds);		FD_SET(f->sock, &master_fds);	}#endif	time(&(f->owner->last_transfer));		if (f->dir_listing) {		/* include size? */		numeric(f->owner, 150, "Opening ASCII mode data connection for directory listing.");	} else {		/*		 * slightly kludged -- perhaps we should kill the second arm,		 * at the expense of code size? Or perhaps we could collapse		 * the two possible replies into one?		 */#if WANT_ASCII		if (f->ascii_mode#if WANT_UPLOAD			|| f->upload#endif /* WANT_UPLOAD */		) {			numeric(f->owner, 150, "Opening %s mode data connection for '%s'",				(f->ascii_mode) ? "ASCII" : "BINARY", f->filename);		} else {			numeric(f->owner, 150, "Opening %s mode data connection for '%s' (%u bytes)",				(f->ascii_mode) ? "ASCII" : "BINARY", f->filename,				f->size); 		}#else /* !WANT_ASCII */#if WANT_UPLOAD		if (f->upload) {			numeric(f->owner, 150, "Opening BINARY mode data connection for '%s'", f->filename);		} else#endif /* WANT_UPLOAD */			numeric(f->owner, 150, "Opening BINARY mode data connection for '%s' (%u bytes)", f->filename, f->size);#endif /* !WANT_ASCII */	}	/*	 * This section _could_ in theory be more optimized, but it's	 * much easier this way, and hopefully, the compiler will be	 * intelligent enough to optimize most of this away. The idea	 * is, some modes _require_ use of mmap (or not). The preferred	 * thing is using mmap() when we don't have sendfile(), and not	 * using mmap() when we have sendfile().	 */#if HAVE_MMAP	if (f->dir_listing == 0) {#if HAVE_LINUX_SENDFILE		int do_mmap = (sendfile_supported) ? 0 : 1;#else		int do_mmap = 1;#endif#if WANT_ASCII		if (f->ascii_mode == 1) do_mmap = 1;#endif#if WANT_UPLOAD                if (f->upload == 1) do_mmap = 0;#endif 		if (do_mmap == 1) {			f->file_data = mmap(NULL, f->size, PROT_READ, MAP_SHARED, f->local_file, 0);			if (f->file_data == MAP_FAILED) f->file_data = NULL;		} else {			f->file_data = NULL;		}		f->pos = f->owner->rest_pos;	}#else /* !HAVE_MMAP */	lseek(f->local_file, f->owner->rest_pos, SEEK_SET);#endif}/* * create_server_socket(): *		Create and bind a server socket, that we can use to *		listen to new clients on. */int create_server_socket(){	int server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);	const unsigned int one = 1;	struct sockaddr_in addr;	int err;		/*	 * In the `perfect' world, if an address was in use, we could	 * just wait for the kernel to clear everything up, and everybody	 * would be happy. But when you just found out your server socket	 * was invalid, it has to be `re-made', and 3000 users are trying	 * to access your fileserver, I think it's nice that it comes	 * up right away... hence this option.	 */	setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));	ioctl(server_sock, FIONBIO, &one);	/* just in case */	addr.sin_family = AF_INET;	addr.sin_addr.s_addr = INADDR_ANY;	addr.sin_port = htons(FTP_PORT);	do {	        err = bind(server_sock, (struct sockaddr *)&addr, sizeof(struct sockaddr));	        if (err == -1) {	                perror("bind()");					/* try to recover from recoverable errors... */			if (errno == ENOMEM || errno == EADDRINUSE) {				puts("Waiting 1 sec before trying again...");				sleep(1);			} else {				puts("Giving up.");	                        exit(1); 	                }	        }	} while (err == -1);	listen(server_sock, 20);	err = add_fd(server_sock, POLLIN);	if (err) {		perror("add_fd");		return -1;	}	return server_sock;}#if !HAVE_POLL/* * clear_bad_fds(): *		Try to find invalid socket descriptors, and clean them. *		The methods used are rather UGLY, but I can't think of *		any good way of checking e.g. server_sock without *		doing anything to it :-( * *		poll() is able to do this in a much cleaner way, which  *		we use if we use poll(). That checking isn't done here, *		though. */void clear_bad_fds(int * const server_sock){	{		fd_set fds;		struct timeval tv = { 0, 0 };		FD_ZERO(&fds);		FD_SET(*server_sock, &fds); 		if (select(*server_sock, &fds, NULL, NULL, &tv) == -1) {			FD_CLR(*server_sock, &master_fds);			close(*server_sock);			*server_sock = create_server_socket();		}	}	/* could do this (conn, ftran) in any order */	{		struct conn *c = NULL, *next = first_conn->next_conn;			/* run through the linked list */		while (next != NULL) {			char buf[1];	        	c = next;	        	next = c->next_conn;			if (read(c->sock, &buf, 0) == -1 &&			    errno == EBADF) {				destroy_conn(c);			}		}	}	{		struct ftran *f = NULL, *next = first_ftran->next_ftran;			while (next != NULL) {			char buf[1];			f = next;			next = f->next_ftran;			if (read(f->sock, &buf, 0) == -1 &&			    errno == EBADF) {				destroy_ftran(f);			}		}	}	}#endif#if WANT_MESSAGE/* * dump_file(): Dumps a file on the control connection. Used for *		welcome messages and the likes. Note that outbuf *		is so big, to prevent any crashing from users creating *		weird .message files (like 1024 LFs)... The size of *		the file is limited to 1024 bytes (by truncation). */void dump_file(struct conn * const c, const int num, const char * const filename){	char buf[1024], outbuf[5121];	char *ptr = outbuf + 4;	int i, j = -1;	const int dumpfile = open(filename, O_RDONLY);	if (dumpfile == -1) return;	i = read(dumpfile, buf, 1024);	if (i <= 0) {		close(dumpfile);		return;	}	sprintf(outbuf, "%03u-", num);	while (++j < i) {		*ptr++ = buf[j];		if (buf[j] == '\n') {			sprintf(ptr, "%03u-", num);			ptr += 4;		}	}	*ptr++ = '\n';	send(c->sock, outbuf, ptr - outbuf, 0);	close(dumpfile);}/* * list_readme(): *		Lists all README file in the current (ie. OS current) *		directory, in a 250- message. */void list_readmes(struct conn * const c){	glob_t pglob;	const time_t now = time(NULL);	int i;	if (glob("README*", 0, NULL, &pglob) != 0) return;	for (i = 0; i < pglob.gl_pathc; i++) {		struct stat buf;		char str[256];		char *tm;		if (stat(pglob.gl_pathv[i], &buf) == -1) continue;		/* remove trailing LF */		tm = ctime(&buf.st_mtime);		tm[strlen(tm) - 1] = 0;		snprintf(str, 256, "250-Please read the file %s\r\n"				   "250-\tIt was last modified %s - %ld days ago\r\n",			pglob.gl_pathv[i], tm,			(now - buf.st_mtime) / 86400);		send(c->sock, str, strlen(str), 0);	}	globfree(&pglob);}#endif

⌨️ 快捷键说明

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