X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=ftpd.c;h=d7f460621d8013a9d6cc08811093583e95cc4af0;hb=e0caa4ef5e987cbea6b570cb5e011e8fd082355a;hp=757c109e677d88091e8b513e9f16124f27d1e695;hpb=85c74b6283f53e8deeab46354a4d3971039b6d56;p=betaftpd diff --git a/ftpd.c b/ftpd.c index 757c109..d7f4606 100644 --- a/ftpd.c +++ b/ftpd.c @@ -2,7 +2,7 @@ Copyright (C) 1999-2000 Steinar H. Gunderson This program is is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License, version 2 if the + it under the terms of the GNU General Public License, version 2 of the License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, @@ -28,10 +28,6 @@ #include #endif -#if HAVE_SYS_TYPES_H -#include -#endif - #if HAVE_ERRNO_H #include #endif @@ -76,10 +72,6 @@ #include #endif -#if HAVE_NETINET_IN_H -#include -#endif - #if HAVE_ARPA_INET_H #include #endif @@ -88,10 +80,6 @@ #include #endif -#if HAVE_SYS_SOCKET_H -#include -#endif - #if HAVE_SYS_IOCTL_H #include #endif @@ -112,6 +100,10 @@ #include #endif +#if HAVE_LINUX_TCP_H +#include +#endif + #if HAVE_MMAP #include #endif @@ -171,6 +163,10 @@ #include #endif +#if WANT_DCACHE +#include +#endif + #ifndef MAP_FAILED #define MAP_FAILED -1 #endif @@ -198,6 +194,10 @@ fd_set master_fds, master_send_fds; FILE *xferlog = NULL; #endif +#if HAVE_LINUX_SENDFILE +int sendfile_supported = 1; +#endif + /* * This variable specifies if it's soon time to check for timed out * clients, and timed out directory listing cache entries. It is @@ -439,30 +439,6 @@ struct ftran *alloc_new_ftran(const int sock, const struct conn * const c) return f; } -#if WANT_DCACHE -/* - * alloc_new_dcache(): - * Allocates a new directory cache entry (type `struct dcache'), - * and adds it to the linked list. - */ -struct dcache *alloc_new_dcache() -{ - struct dcache *d = (struct dcache *)(malloc(sizeof(struct dcache))); - - if (d == NULL) return d; - - d->use_count = 0; - d->last_used = 0; - strcpy(d->dir_name, ""); - d->dir_data = NULL; - - add_to_linked_list((struct list_element *)first_dcache, - (struct list_element *)d); - - return d; -} -#endif - /* * destroy_conn(): * Destroy a control connection, remove it from the linked @@ -534,30 +510,9 @@ void destroy_ftran(struct ftran * const f) remove_from_linked_list((struct list_element *)f); } -#if WANT_DCACHE -/* - * destroy_dcache(): - * Destroy a directory listing cache entry, remove it from the - * linked list, and clean up after it. - * - * If you free a cache entry that is in use (use_count > 0), - * BetaFTPD will most likely crash (later). The thing you're supposed - * to do when you're done with a dcache entry, is to decrement - * its use_count, and let the timeout functions do the destroying - * when it's time to do so. - */ -void destroy_dcache(struct dcache * const d) -{ - if (d == NULL) return; - - if (d->dir_data != NULL) free(d->dir_data); - remove_from_linked_list((struct list_element *)d); -} -#endif - /* * process_all_clients(): - * Processes all the control connections in active_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 @@ -579,7 +534,7 @@ int process_all_clients(const fd_set * const active_clients, const int num_ac) c = next; next = c->next_conn; #if HAVE_POLL - if (!fds[c->sock].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL)) { + if ((fds[c->sock].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL)) == 0) { continue; } #else @@ -620,12 +575,34 @@ int process_all_clients(const fd_set * const active_clients, const int num_ac) if (fds[c->sock].revents & (POLLERR|POLLHUP|POLLNVAL)) { destroy_conn(c); - continue; } } return checked_through; } +/* + * finish_transfer(): + * Send a message that the transfer is completed, write xferlog + * entry (optional), and update the last_transfer record in the + * file transfer object. Goes for both uploads and downloads. + */ +void finish_transfer(struct ftran * const f) +{ + 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 +} + /* * process_all_sendfiles(): * Sends data to all clients that are ready to receive it. @@ -647,8 +624,15 @@ int process_all_sendfiles(fd_set * const active_clients, const int num_ac) f = next; next = f->next_ftran; +#if HAVE_UPLOAD + if (f->upload == 1 && fds[f->sock].revents & POLLHUP) { + finish_transfer(f); + continue; + } +#endif + #if HAVE_POLL - if (fds[f->sock].revents & (POLLHUP|POLLERR|POLLNVAL)) { + if (fds[f->sock].revents & (POLLERR|POLLNVAL|POLLHUP)) { destroy_ftran(f); continue; } @@ -656,7 +640,7 @@ int process_all_sendfiles(fd_set * const active_clients, const int num_ac) /* 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) { + 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 @@ -706,16 +690,7 @@ int process_all_sendfiles(fd_set * const active_clients, const int num_ac) 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); + finish_transfer(f); #if WANT_FULLSCREEN update_display(first_conn); #endif @@ -791,11 +766,7 @@ int do_download(struct ftran *f) * Here we use a rather simplified sending `algorithm', * leaving most of the quirks to the system calls. */ - if (f->dir_listing == 0 -#if WANT_UPLOAD - && f->upload == 0 -#endif - ) { + if (sendfile_supported == 1 && f->dir_listing == 0) { int err; size = f->size - f->pos; @@ -1002,6 +973,19 @@ int main(void) 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 @@ -1179,29 +1163,6 @@ void time_out_sockets() } } -#if WANT_DCACHE -/* - * time_out_dcache(): - * Time out expired directory listing cache entries. - * Uses much of the same code as time_out_sockets(). - */ -void time_out_dcache() -{ - struct dcache *d = NULL, *next = first_dcache->next_dcache; - time_t now = time(NULL); - - /* run through the linked list */ - while (next != NULL) { - d = next; - next = d->next_dcache; - - if (d->use_count == 0 && (now - d->last_used > 900)) { - destroy_dcache(d); - } - } -} -#endif - /* * remove_bytes(): * Remove some bytes from the incoming buffer. This gives @@ -1378,7 +1339,7 @@ void init_file_transfer(struct ftran * const f) #if HAVE_MMAP if (f->dir_listing == 0) { #if HAVE_LINUX_SENDFILE - int do_mmap = 0; + int do_mmap = (sendfile_supported) ? 0 : 1; #else int do_mmap = 1; #endif