From: wessels <> Date: Sat, 23 Mar 1996 00:47:10 +0000 (+0000) Subject: change FTP to use a ftpget-daemon so cached does not fork X-Git-Tag: SQUID_3_0_PRE1~6410 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=77a30ebbc5e05009722492f8982a9d99fd1faaac;p=thirdparty%2Fsquid.git change FTP to use a ftpget-daemon so cached does not fork --- diff --git a/src/ftp.cc b/src/ftp.cc index 35c316d9c3..17496e494c 100644 --- a/src/ftp.cc +++ b/src/ftp.cc @@ -1,4 +1,4 @@ -/* $Id: ftp.cc,v 1.6 1996/02/29 07:23:11 wessels Exp $ */ +/* $Id: ftp.cc,v 1.7 1996/03/22 17:47:10 wessels Exp $ */ #include "config.h" #include @@ -9,6 +9,7 @@ #include #include /* for WNOHANG */ #include +#include #include "ansihelp.h" #include "comm.h" @@ -21,6 +22,8 @@ #include "ttl.h" #include "util.h" #include "ftp.h" +#include "icp.h" +#include "cached_error.h" #define FTP_DELETE_GAP (64*1024) @@ -32,33 +35,44 @@ static char ftpBinary[] = "I"; typedef struct _Ftpdata { StoreEntry *entry; - char host[SQUIDHOSTNAMELEN + 1]; char type_id; + char host[SQUIDHOSTNAMELEN + 1]; char request[MAX_URL]; + char user[MAX_URL]; + char password[MAX_URL]; char *type; char *mime_hdr; int cpid; int ftp_fd; + char *icp_page_ptr; /* Used to send proxy-http request: + * put_free_8k_page(me) if the lifetime + * expires */ + char *icp_rwd_ptr; /* When a lifetime expires during the + * middle of an icpwrite, don't lose the + * icpReadWriteData */ } FtpData; extern char *tmp_error_buf; extern time_t cached_curtime; +#ifdef OLD_CODE static int ftp_open_pipe(); static int ftp_close_pipe(); +#endif /* XXX: this does not support FTP on a different port! */ -int ftp_url_parser(url, host, request, user, password) +int ftp_url_parser(url, data) char *url; - char *host; - char *request; - char *user; - char *password; + FtpData *data; { static char atypebuf[MAX_URL]; static char hostbuf[MAX_URL]; char *tmp = NULL; int t; + char *host = data->host; + char *request = data->request; + char *user = data->user; + char *password = data->password; /* initialize everything */ atypebuf[0] = hostbuf[0] = '\0'; @@ -129,26 +143,14 @@ void ftpLifetimeExpire(fd, data) StoreEntry *entry = NULL; entry = data->entry; debug(4, "ftpLifeTimeExpire: FD %d: \n", fd, entry->url); - sprintf(tmp_error_buf, CACHED_RETRIEVE_ERROR_MSG, - entry->url, - entry->url, - "FTP", - 210, - "Transaction Timeout", - "The Network/Remote site may be down or too slow. Try again later.", - SQUID_VERSION, - comm_hostname()); - storeAbort(entry, tmp_error_buf); - ftp_close_pipe(data->ftp_fd, data->cpid); + if (data->icp_page_ptr) { + put_free_8k_page(data->icp_page_ptr); + data->icp_page_ptr = NULL; + } + safe_free(data->icp_rwd_ptr); + cached_error(entry, ERR_LIFETIME_EXP); + /* ftp_close_pipe(data->ftp_fd, data->cpid); */ comm_close(fd); -#ifdef LOG_ERRORS - CacheInfo->log_append(CacheInfo, - entry->url, - "0.0.0.0", - entry->mem_obj->e_current_len, - "ERR_210", /* FTP LIFETIME EXPIRE */ - data->type ? data->type : "NULL"); -#endif safe_free(data); } @@ -188,66 +190,36 @@ int ftpReadReply(fd, data) } } else { /* we can terminate connection right now */ - sprintf(tmp_error_buf, CACHED_RETRIEVE_ERROR_MSG, - entry->url, - entry->url, - "FTP", - 319, - "No Client", - "All Clients went away before tranmission is complete and object is too big to cache.", - SQUID_VERSION, - comm_hostname()); - storeAbort(entry, tmp_error_buf); - ftp_close_pipe(data->ftp_fd, data->cpid); + cached_error(entry, ERR_NO_CLIENTS_BIG_OBJ); + /* ftp_close_pipe(data->ftp_fd, data->cpid); */ comm_close(fd); -#ifdef LOG_ERRORS - CacheInfo->log_append(CacheInfo, - entry->url, - "0.0.0.0", - entry->mem_obj->e_current_len, - "ERR_319", /* FTP NO CLIENTS, BIG OBJECT */ - data->type ? data->type : "NULL"); -#endif safe_free(data); return 0; } } len = read(fd, buf, 4096); - debug(5, "ftpReadReply FD %d, len=%d\n", fd, len); + debug(5, "ftpReadReply FD %d, Read %d bytes\n", fd, len); if (len < 0 || ((len == 0) && (entry->mem_obj->e_current_len == 0))) { if (len < 0) debug(1, "ftpReadReply - error reading: %s\n", xstrerror()); - sprintf(tmp_error_buf, CACHED_RETRIEVE_ERROR_MSG, - entry->url, - entry->url, - "FTP", - 305, - "Read Error.", - "Network/Remote Site is down. Try again later.", - SQUID_VERSION, - comm_hostname()); - storeAbort(entry, tmp_error_buf); - ftp_close_pipe(data->ftp_fd, data->cpid); + cached_error(entry, ERR_READ_ERROR); + /* ftp_close_pipe(data->ftp_fd, data->cpid); */ comm_close(fd); -#ifdef LOG_ERRORS - CacheInfo->log_append(CacheInfo, - entry->url, - "0.0.0.0", - entry->mem_obj->e_current_len, - "ERR_305", /* FTP READ ERROR */ - data->type ? data->type : "NULL"); -#endif safe_free(data); } else if (len == 0) { /* Connection closed; retrieval done. */ /* If ftpget failed, arrange so the object gets ejected and * doesn't get to disk. */ + /* XXX REALLY NEED TO THINK ABOUT THIS */ +#ifdef OLD_CODE if (ftp_close_pipe(data->ftp_fd, data->cpid) != 0) { entry->expires = cached_curtime + getNegativeTTL(); BIT_RESET(entry->flag, CACHABLE); BIT_SET(entry->flag, RELEASE_REQUEST); - } else if (!(entry->flag & DELETE_BEHIND)) { + } else +#endif + if (!(entry->flag & DELETE_BEHIND)) { entry->expires = cached_curtime + ttlSet(entry); } /* update fdstat and fdtable */ @@ -268,26 +240,9 @@ int ftpReadReply(fd, data) } else if (entry->flag & CLIENT_ABORT_REQUEST) { /* append the last bit of info we get */ storeAppend(entry, buf, len); - sprintf(tmp_error_buf, CACHED_RETRIEVE_ERROR_MSG, - entry->url, - entry->url, - "FTP", - 307, - "Client Aborted", - "Client(s) dropped connection before transmission is complete.\nObject fetching is aborted.\n", - SQUID_VERSION, - comm_hostname()); - storeAbort(entry, tmp_error_buf); - ftp_close_pipe(data->ftp_fd, data->cpid); + cached_error(entry, ERR_CLIENT_ABORT); + /* ftp_close_pipe(data->ftp_fd, data->cpid); */ comm_close(fd); -#ifdef LOG_ERRORS - CacheInfo->log_append(CacheInfo, - entry->url, - "0.0.0.0", - entry->mem_obj->e_current_len, - "ERR_307", /* FTP CLIENT ABORT */ - data->type ? data->type : "NULL"); -#endif safe_free(data); } else { storeAppend(entry, buf, len); @@ -304,15 +259,172 @@ int ftpReadReply(fd, data) return 0; } +void ftpSendComplete(fd, buf, size, errflag, data) + int fd; + char *buf; + int size; + int errflag; + FtpData *data; +{ + StoreEntry *entry = NULL; + + entry = data->entry; + debug(5, "ftpSendComplete: FD %d: size %d: errflag %d.\n", + fd, size, errflag); + + if (buf) { + put_free_8k_page(buf); /* Allocated by ftpSendRequest. */ + buf = NULL; + } + data->icp_page_ptr = NULL; /* So lifetime expire doesn't re-free */ + data->icp_rwd_ptr = NULL; /* Don't double free in lifetimeexpire */ + + if (errflag) { + cached_error(entry, ERR_CONNECT_FAIL, xstrerror()); + comm_close(fd); + safe_free(data); + return; + } else { + comm_set_select_handler(data->ftp_fd, + COMM_SELECT_READ, + (PF) ftpReadReply, + (caddr_t) data); + comm_set_select_handler_plus_timeout(data->ftp_fd, + COMM_SELECT_TIMEOUT, + (PF) ftpLifetimeExpire, + (caddr_t) data, getReadTimeout()); + } +} + +void ftpSendRequest(fd, data) + int fd; + FtpData *data; +{ + char *ext = NULL; + ext_table_entry *e = NULL; + int l; + char *path = NULL; + char *mode = NULL; + char *buf = NULL; + static char tbuf[BUFSIZ]; + static char opts[BUFSIZ]; + static char *space = " "; + static char *w_space = " \t\r\n"; + char *s = NULL; + int got_timeout = 0; + int got_negttl = 0; + int buflen; + + debug(5, "ftpSendRequest: FD %d\n", fd); + + buflen = strlen(data->request) + 256; + buf = (char *) get_free_8k_page(); + data->icp_page_ptr = buf; + memset(buf, '\0', buflen); + + path = data->request; + l = strlen(path); + if (path[l - 1] == '/') + mode = ftpASCII; + else { + if ((ext = strrchr(path, '.')) != NULL) { + ext++; + mode = ((e = mime_ext_to_type(ext)) && + strncmp(e->mime_type, "text", 4) == 0) ? ftpASCII : + ftpBinary; + } else + mode = ftpBinary; + } + + /* Remove leading slash from FTP url-path so that we can + * handle ftp://user:pw@host/path objects where path and /path + * are quite different. -DW */ + if (!strcmp(path, "/")) + *path = '.'; + if (*path == '/') + path++; + + /* Start building the buffer ... */ + + strcat(buf, getFtpProgram()); + strcat(buf, space); + + strncpy(opts, getFtpOptions(), BUFSIZ); + for (s = strtok(opts, w_space); s; s = strtok(NULL, w_space)) { + strcat(buf, s); + strcat(buf, space); + if (!strncmp(s, "-t", 2)) + got_timeout = 1; + if (!strncmp(s, "-n", 2)) + got_negttl = 1; + } + if (!got_timeout) { + sprintf(tbuf, "-t %d ", getReadTimeout()); + strcat(buf, tbuf); + } + if (!got_negttl) { + sprintf(tbuf, "-n %d ", getNegativeTTL()); + strcat(buf, tbuf); + } + strcat(buf, "-h "); /* httpify */ + strcat(buf, "- "); /* stdout */ + strcat(buf, data->host); + strcat(buf, space); + strcat(buf, path); + strcat(buf, space); + strcat(buf, mode); /* A or I */ + strcat(buf, space); + strcat(buf, data->user); + strcat(buf, space); + strcat(buf, data->password); + strcat(buf, space); + debug(5, "ftpSendRequest: FD %d: buf '%s'\n", fd, buf); + data->icp_rwd_ptr = icpWrite(fd, buf, strlen(buf), 30, ftpSendComplete, data); +} + +void ftpConnInProgress(fd, data) + int fd; + FtpData *data; +{ + StoreEntry *entry = data->entry; + + debug(5, "ftpConnInProgress: FD %d\n", fd); + + if (comm_connect(fd, "localhost", 3131) != COMM_OK) + switch (errno) { + case EINPROGRESS: + case EALREADY: + /* schedule this handler again */ + comm_set_select_handler(fd, + COMM_SELECT_WRITE, + (PF) ftpConnInProgress, + (caddr_t) data); + return; + case EISCONN: + debug(5, "ftpConnInProgress: FD %d is now connected.", fd); + break; /* cool, we're connected */ + default: + comm_close(fd); + cached_error(entry, ERR_CONNECT_FAIL, xstrerror()); + safe_free(data); + return; + } + /* Call the real write handler, now that we're fully connected */ + comm_set_select_handler(fd, + COMM_SELECT_WRITE, + (PF) ftpSendRequest, + (caddr_t) data); +} + + int ftpStart(unusedfd, url, entry) int unusedfd; char *url; StoreEntry *entry; { - static char user[MAX_URL]; - static char password[MAX_URL]; FtpData *data = NULL; + int status; debug(3, "FtpStart: FD %d \n", unusedfd, url); @@ -320,91 +432,97 @@ int ftpStart(unusedfd, url, entry) data->entry = entry; /* Parse url. */ - user[0] = password[0] = '\0'; - if (ftp_url_parser(url, data->host, data->request, user, password)) { - sprintf(tmp_error_buf, CACHED_RETRIEVE_ERROR_MSG, - entry->url, - entry->url, - "FTP", - 309, - "Invalid URL syntax: Cannot parse.", - "Please contact your system manager for further help.", - SQUID_VERSION, - comm_hostname()); - storeAbort(entry, tmp_error_buf); -#ifdef LOG_ERRORS - CacheInfo->log_append(CacheInfo, - entry->url, - "0.0.0.0", - entry->mem_obj->e_current_len, - "ERR_309", /* FTP INVALID URL */ - data->type ? data->type : "NULL"); -#endif + if (ftp_url_parser(url, data)) { + cached_error(entry, ERR_INVALID_URL); safe_free(data); return COMM_ERROR; } - debug(5, "FtpStart - host:%s, request:%s, user:%s, passwd:%s\n", - data->host, data->request, user, password); - - /* Create socket. */ - data->ftp_fd = ftp_open_pipe(getFtpProgram(), - data->host, - data->request, - user, - password, - "r", - &(data->cpid), - getFtpOptions()); - - if (data->ftp_fd < 0) { - sprintf(tmp_error_buf, CACHED_RETRIEVE_ERROR_MSG, - entry->url, - entry->url, - "FTP", - 308, - "Cannot connect to FTP slave process", - "Please contact your system manager for further help.", - SQUID_VERSION, - comm_hostname()); - storeAbort(entry, tmp_error_buf); -#ifdef LOG_ERRORS - CacheInfo->log_append(CacheInfo, - entry->url, - "0.0.0.0", - entry->mem_obj->e_current_len, - "ERR_308", /* FTP FTPGET FAIL */ - data->type ? data->type : "NULL"); -#endif + debug(5, "FtpStart: FD %d, host=%s, request=%s, user=%s, passwd=%s\n", + unusedfd, data->host, data->request, data->user, data->password); + + data->ftp_fd = comm_open(COMM_NONBLOCKING, 0, 0, url); + if (data->ftp_fd == COMM_ERROR) { + cached_error(entry, ERR_CONNECT_FAIL, xstrerror()); safe_free(data); return COMM_ERROR; } - /* Pipe created ok */ - - debug(5, "startftp - conn %d EINPROGRESS\n", data->ftp_fd); + /* Pipe/socket created ok */ - fdstat_open(data->ftp_fd, Pipe); + /* Now connect ... */ + if ((status = comm_connect(data->ftp_fd, "localhost", 3131))) { + if (status != EINPROGRESS) { + comm_close(data->ftp_fd); + cached_error(entry, ERR_CONNECT_FAIL, xstrerror()); + safe_free(data); + return COMM_ERROR; + } else { + debug(5, "ftpStart: FD %d: EINPROGRESS.\n", data->ftp_fd); + comm_set_select_handler(data->ftp_fd, COMM_SELECT_LIFETIME, + (PF) ftpLifetimeExpire, (caddr_t) data); + comm_set_select_handler(data->ftp_fd, COMM_SELECT_WRITE, + (PF) ftpConnInProgress, (caddr_t) data); + return COMM_OK; + } + } + fdstat_open(data->ftp_fd, Socket); commSetNonBlocking(data->ftp_fd); (void) fd_note(data->ftp_fd, entry->url); /* Install connection complete handler. */ fd_note(data->ftp_fd, entry->url); - comm_set_select_handler(data->ftp_fd, COMM_SELECT_WRITE, 0, 0); - comm_set_fd_lifetime(data->ftp_fd, getClientLifetime()); comm_set_select_handler(data->ftp_fd, - COMM_SELECT_LIFETIME, - (PF) ftpLifetimeExpire, + COMM_SELECT_WRITE, + (PF) ftpSendRequest, (caddr_t) data); + comm_set_fd_lifetime(data->ftp_fd, + getClientLifetime()); comm_set_select_handler(data->ftp_fd, - COMM_SELECT_READ, - (PF) ftpReadReply, - (caddr_t) data); - comm_set_select_handler_plus_timeout(data->ftp_fd, - COMM_SELECT_TIMEOUT, + COMM_SELECT_LIFETIME, (PF) ftpLifetimeExpire, - (caddr_t) data, getReadTimeout()); + (caddr_t) data); + return COMM_OK; } +int ftpInitialize() +{ + int pid; + int fd; + int p[2]; + static char pbuf[128]; + char *ftpget = getFtpProgram(); + + if (pipe(p) < 0) { + debug(0, "ftpInitialize: pipe: %s\n", xstrerror()); + return -1; + } + if ((pid = fork()) < 0) { + debug(0, "ftpInitialize: fork: %s\n", xstrerror()); + return -1; + } + if (pid != 0) { /* parent */ + close(p[0]); + fdstat_open(p[1], Pipe); + fd_note(p[1], "ftpget -S"); + fcntl(p[1], F_SETFD, 1); /* set close-on-exec */ + return 0; + } + /* child */ + close(0); + dup(p[0]); + close(p[0]); + close(p[1]); + /* inherit stdin,stdout,stderr */ + for (fd = 3; fd < fdstat_biggest_fd(); fd++) + (void) close(fd); + sprintf(pbuf, "%d", 3131); + execlp(ftpget, ftpget, "-D26,1", "-S", pbuf, NULL); + debug(0, "ftpInitialize: %s: %s\n", ftpget, xstrerror()); + _exit(1); + return (1); /* eliminate compiler warning */ +} + +#ifdef OLD_CODE /* * ftp_open_pipe - This opens a pipe to the ftpget command. * It currently supports read-only pipes and hardcoded args. The child @@ -547,7 +665,7 @@ static int ftp_open_pipe(p1, p2, p3, p4, p5, type, cpid, opts) execvp(p1, argv); perror(p1); _exit(1); - return (0); /* NOTREACHED */ + return (0); /* NOTREACHED */ } /* @@ -638,3 +756,4 @@ static int ftp_close_pipe(fd, cpid) } return 0; } +#endif