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

📄 ftpd.c

📁 ftp服务器源程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * process_all_clients(): *		Processes all the _control_ connections in active_clients *		(normally returned from a select(), there are at max *		NUM_AC active connections in the set), sending them *		through to the command parser if a command has been *		entered. */#if HAVE_POLLint process_all_clients(const int num_ac)#elseint process_all_clients(const fd_set * const active_clients, const int num_ac)#endif{	struct conn *c = NULL, *next = first_conn->next_conn;	int checked_through = 0;	/* run through the linked list */	while (next != NULL && checked_through < num_ac) {		int bytes_avail;		c = next;		next = c->next_conn;#if HAVE_POLL		if ((fds[c->sock].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL)) == 0) {			continue;		}#else		if (!FD_ISSET(c->sock, active_clients)) {			continue;		}#endif		checked_through++;		bytes_avail = recv(c->sock, c->recv_buf + c->buf_len,				   255 - c->buf_len, 0);		if (bytes_avail <= 0) {			/*			 * select() has already told us there's something about			 * this socket, so if we get a return value of zero, the			 * client has closed the socket. If we get a return value			 * of -1 (error), we close the socket ourselves.			 *			 * We do the same for poll(), even though we actually have			 * bits that tell us what is happening (in case of new 			 * input AND error/hangup at the same time, we do an			 * explicit check at the bottom of the loop as well).			 */			destroy_conn(c);			continue;		}		/* overrun = disconnect */		if (c->buf_len + bytes_avail > 254) {			numeric(c, 503, "Buffer overrun; disconnecting.");			destroy_conn(c);			continue;		}		c->buf_len += bytes_avail;		parse_command(c);		if (fds[c->sock].revents & (POLLERR|POLLHUP|POLLNVAL)) {                        destroy_conn(c);                }	}	return checked_through;}/* * process_all_sendfiles(): *		Sends data to all clients that are ready to receive it. *		Also checks for data connections that are newly-connected, *		and handler xferlog entries for the files that are finished. */#if HAVE_POLLint process_all_sendfiles(const int num_ac)#elseint process_all_sendfiles(fd_set * const active_clients, const int num_ac)#endif{	struct ftran *f = NULL, *next = first_ftran->next_ftran;	int checked_through = 0;	struct sockaddr tempaddr;	int tempaddr_len = sizeof(tempaddr); 	while (next != NULL && checked_through < num_ac) {		f = next;		next = f->next_ftran;#if HAVE_POLL		if (fds[f->sock].revents & (POLLHUP|POLLERR|POLLNVAL)) {			destroy_ftran(f);			continue;		}#endif		/* state = 2: incoming PASV, state >3: send file */#if HAVE_POLL		if ((f->state < 2) || (f->state == 3) ||  (fds[f->sock].revents & (POLLIN|POLLOUT)) == 0) {#else		if ((f->state < 2) || (f->state == 3) || !FD_ISSET(f->sock, active_clients)) {#endif			continue;		}		checked_through++;#if HAVE_POLL		/* Nothing is needed for the poll() version? */#else		FD_CLR(f->sock, active_clients);#endif		if (f->state == 2) {		/* incoming PASV */			const unsigned int one = 1;			const int tempsock = accept(f->sock, (struct sockaddr *)&tempaddr,							&tempaddr_len);			del_fd(f->sock);			if (tempsock == -1) {				destroy_ftran(f);				continue;			}			f->sock = tempsock;			ioctl(f->sock, FIONBIO, &one);			init_file_transfer(f);#if WANT_UPLOAD	                if (f->upload) continue;#endif		}		if (f->state < 5) {			init_file_transfer(f);#if WANT_UPLOAD	                if (f->upload) continue;#endif		}		/* for download, we send the first packets right away */#if WANT_UPLOAD		if (f->upload) {			if (do_upload(f)) continue;		} else#endif			if (do_download(f)) continue;		/* do_{upload,download} returned 0, the transfer is complete */                numeric(f->owner, 226, "Transfer complete.");                time(&(f->owner->last_transfer));#if WANT_XFERLOG                if (!f->dir_listing) {			write_xferlog(f);		}#endif		destroy_ftran(f);#if WANT_FULLSCREEN                update_display(first_conn);#endif        }        return checked_through;}#if WANT_UPLOADint do_upload(struct ftran *f){	char upload_buf[16384];	int size;#if WANT_ASCII	/* keep buffer size small in ascii transfers 	   to prevent process stalling while filtering	   data on slower computers */	/* 	 * This isn't a big problem, since we won't get	 * packets this big anyway, the biggest I've seen	 * was 12kB on 100mbit (but that was from a Windows	 * machine), so I've reduced the buffer from 64 kB	 * to 16 kB :-) --Steinar	 */	const int maxlen = (f->ascii_mode == 1) ? 4096 : 16384;#else	const int maxlen = 16384;#endif	errno = 0;	size = recv(f->sock, upload_buf, maxlen, 0);	if (size >= 0) {		f->pos += size;	}#if WANT_ASCII	if (size > 0 && f->ascii_mode == 1) {		size = ascii_uploadfilter(upload_buf, size);	}#endif	if (size > 0 && (write(f->local_file, upload_buf, size) == size)) {		return 1;	} else if (size == -1) {		/* don't write xferlog... or? */		numeric(f->owner, 426, strerror(errno));		destroy_ftran(f);		return 1;	}	return 0;} #endifint do_download(struct ftran *f){#if defined(TCP_CORK) && defined(SOL_TCP)	unsigned int zero = 0;#endif	char *sendfrom_buf;	int bytes_to_send;	int more_to_send = 0;#if !HAVE_MMAP	char buf[MAX_BLOCK_SIZE];#endif#if WANT_ASCII	char buf2[MAX_BLOCK_SIZE * 2];#endif	int size;#if HAVE_LINUX_SENDFILE	/*	 * We handle the optimal case first, which is sendfile().	 * Here we use a rather simplified sending `algorithm',	 * leaving most of the quirks to the system calls.	 */	if (sendfile_supported == 1 && f->dir_listing == 0) {		int err;		size = f->size - f->pos;		if (size > f->block_size) size = f->block_size;		if (size < 0) size = 0;#ifdef TCP_CORK		if (size != f->block_size) {                	setsockopt(f->sock, SOL_TCP, TCP_CORK, (void *)&zero, sizeof(zero));        	}	#endif       		err = sendfile(f->sock, f->local_file, &f->pos, size);		return (f->pos < f->size) && (err > -1);	}#endif#if HAVE_MMAP        size = f->size - f->pos;        if (size > f->block_size) size = f->block_size;        if (size < 0) size = 0;	bytes_to_send = size;	sendfrom_buf = f->file_data + f->pos;#else	bytes_to_send = read(f->local_file, buf, f->block_size);	sendfrom_buf = buf;#endif	if (bytes_to_send == f->block_size) more_to_send = 1;#if WANT_ASCII	if (f->ascii_mode == 1) {		bytes_to_send = ascii_downloadfilter(sendfrom_buf,			      			     buf2, bytes_to_send);		sendfrom_buf = buf2;       	}#endif /* WANT_ASCII */#if defined(TCP_CORK) && defined(SOL_TCP)	/* if we believe this is the last packet, unset TCP_CORK */	if (more_to_send == 0) {		setsockopt(f->sock, SOL_TCP, TCP_CORK, (void *)&zero, sizeof(zero));	}#endif	size = send(f->sock, sendfrom_buf, bytes_to_send, 0);	if (size < bytes_to_send) more_to_send = 1;#if WANT_ASCII	if (f->ascii_mode == 1 && size < bytes_to_send && size > 0) {		size = ascii_findlength(sendfrom_buf, size);	}#endif#if HAVE_MMAP	if (size > 0) f->pos += size;#endif	return more_to_send;}#if WANT_XFERLOGvoid write_xferlog(struct ftran *f){      	char temp[256];       	time_t now = time(NULL);       	struct tm *t = localtime(&now);	if (xferlog == NULL) return;	strftime(temp, 256, "%a %b %d %H:%M:%S %Y", t);#if WANT_UPLOAD	fprintf(xferlog, "%s %u %s %lu %s b _ %c a %s ftp 0 * \n",#else    	fprintf(xferlog, "%s %u %s %lu %s b _ o a %s ftp 0 *\n",#endif		temp, (int)(difftime(now, f->tran_start)),		inet_ntoa(f->sin.sin_addr), f->size,		f->filename,#if WANT_UPLOAD		(f->upload) ? 'i' : 'o',#endif		f->owner->username);       	fflush(xferlog);#if 0	/* vim needs this to work properly :-( */	)#endif}#endif#if 0/* Reallocate the buggers constantly */void screw_clients(){	struct conn *c = first_conn;	int maxloops = MAXCLIENTS;	while (c && c->next_conn) {		struct conn *temp = malloc(sizeof(*temp));		if (!temp) break;		*temp = *(c->next_conn);		if (temp->transfer) temp->transfer->owner = temp;		memset(c->next_conn, 0, sizeof(struct conn));		free(c->next_conn);		temp->prev_conn = c;		c->next_conn = temp;		c = c->next_conn;		maxloops--;		assert(maxloops > 0);	}}#endif/* * main():	Main function. Does the initialization, and contains *		the main server loop. Takes no command-line arguments *		(see README for justification). */int main(void){	int server_sock;#if HAVE_POLL	/* the sets are declared globally if we use poll() */#else	fd_set fds, fds_send;#endif	/*setlinebuf(stdout);*/	setvbuf(stdout, (char *)NULL, _IOLBF, 0); 	signal(SIGPIPE, SIG_IGN);	printf("BetaFTPD version %s, Copyright (C) 1999-2000 Steinar H. Gunderson\n", VERSION);	puts("BetaFTPD comes with ABSOLUTELY NO WARRANTY; for details see the file");	puts("COPYING. This is free software, and you are welcome to redistribute it");	puts("under certain conditions; again see the file COPYING for details.");	puts("");	/* we don't need stdin */	close(0);#if HAVE_POLL	{		int i;		for (i = 0; i < FD_MAX; i++) {			fds[i].fd = -1;			fds[i].events = 0;		}	}#else	FD_ZERO(&master_fds);	FD_ZERO(&master_send_fds);#endif	server_sock = create_server_socket();#if WANT_FULLSCREEN	printf("%cc", (char)27);	/* reset and clear the screen */#endif	/* init dummy first connection */	first_conn = alloc_new_conn(-1);	first_ftran = alloc_new_ftran(0, NULL);#if WANT_DCACHE	first_dcache = alloc_new_dcache();#endif#if WANT_XFERLOG#if WANT_NONROOT#warning No xferlog support for nonroot yet#else	/* open xferlog */	xferlog = fopen("/var/log/xferlog", "r+");	if (xferlog == NULL) xferlog = fopen("/usr/adm/xferlog", "r+");	if (xferlog != NULL) {                 fseek(xferlog, 0L, SEEK_END);        }#endif#endif#if WANT_FORK	switch (fork()) {	case -1:		perror("fork()");		puts("fork() failed, exiting");		exit(0);	case 0:		break;	default:		puts("BetaFTPD forked into the background");		exit(0);	}#else	puts("BetaFTPD active");#endif	/* set timeout alarm here (after the fork) */	alarm(60);	signal(SIGALRM, handle_alarm);#if HAVE_LINUX_SENDFILE	/* check that sendfile() is really implemented (same check as configure does) */	{		int out_fd = 1, in_fd = 0;		off_t offset = 0;		size_t size = 1024;		errno = 0;		sendfile(out_fd, in_fd, &offset, size);		if (errno == ENOSYS) sendfile_supported = 0;	}#endif	for ( ;; ) {		int i;#ifndef HAVE_POLL		struct timeval timeout;#endif		/*screw_clients();       //look for memory errors */#if WANT_FULLSCREEN	        update_display(first_conn);#endif#if HAVE_POLL		i = poll(fds, highest_fds + 1, 60000);#if 0		{			int j;			for (j=0; j<=highest_fds; j++) {				if (fds[j].revents) printf("fds[%d].fd %d, .revents %x\n", j, fds[j].fd, fds[j].revents);			}		}#endif#else		/* reset fds (gets changed by select()) */		fds = master_fds;		fds_send = master_send_fds;		/*		 * wait up to 60 secs for any activity 		 */		timeout.tv_sec = 60;		timeout.tv_usec = 0;		i = select(FD_SETSIZE, &fds, &fds_send, NULL, &timeout);#endif		if (i == -1) {			if (errno == EBADF) {#if !HAVE_POLL				/* don't like this, but we have to */				clear_bad_fds(&server_sock);#endif			} else if (errno != EINTR) {#if HAVE_POLL				perror("poll()");#else				perror("select()");#endif				continue;			}		}#if HAVE_POLL		/* fix an invalid server socket */		if (fds[server_sock].revents & POLLERR) {			del_fd(server_sock);			server_sock = create_server_socket();

⌨️ 快捷键说明

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