From 5b74d7e9c7c1f6bdcbae4e658c76c41016cdbf6b Mon Sep 17 00:00:00 2001 From: des Date: Sat, 11 Jul 1998 18:56:01 +0000 Subject: Too many changes to list. Basically, FTP is nearly there and error reporting is kinda sorted out. Now HTTP needs to catch up... --- lib/libfetch/Makefile | 8 +- lib/libfetch/fetch.c | 37 +++++- lib/libfetch/fetch.h | 13 +- lib/libfetch/ftp.c | 330 +++++++++++++++++++++++++++++++++++--------------- lib/libfetch/http.c | 52 +++----- 5 files changed, 302 insertions(+), 138 deletions(-) (limited to 'lib/libfetch') diff --git a/lib/libfetch/Makefile b/lib/libfetch/Makefile index ad502d1..3ee090b 100644 --- a/lib/libfetch/Makefile +++ b/lib/libfetch/Makefile @@ -21,9 +21,9 @@ ftperr.c: ftp.errors | grep -v ^# \ | sort \ | while read NUM STRING; do \ - echo " { $${NUM}, \"$${NUM} $${STRING}\" },"; \ + echo " { $${NUM}, \"$${STRING}\" },"; \ done >> ${.TARGET} - @echo " { 0, \"Unknown FTP error\" }" >> ${.TARGET} + @echo " { -1, \"Unknown FTP error\" }" >> ${.TARGET} @echo "};" >> ${.TARGET} httperr.c: http.errors @@ -36,9 +36,9 @@ httperr.c: http.errors | grep -v ^# \ | sort \ | while read NUM STRING; do \ - echo " { $${NUM}, \"$${NUM} $${STRING}\" },"; \ + echo " { $${NUM}, \"$${STRING}\" },"; \ done >> ${.TARGET} - @echo " { 0, \"Unknown HTTP error\" }" >> ${.TARGET} + @echo " { -1, \"Unknown HTTP error\" }" >> ${.TARGET} @echo "};" >> ${.TARGET} .include diff --git a/lib/libfetch/fetch.c b/lib/libfetch/fetch.c index 99a2b9f..9e60938 100644 --- a/lib/libfetch/fetch.c +++ b/lib/libfetch/fetch.c @@ -25,15 +25,20 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id$ + * $Id: fetch.c,v 1.1.1.1 1998/07/09 16:52:42 des Exp $ */ #include +#include +#include +#include #include +#include #include #include #include +#include #include "fetch.h" @@ -43,6 +48,8 @@ #define DEBUG(x) do { } while (0) #endif +int fetchLastErrCode; +const char *fetchLastErrText; /* get URL */ FILE * @@ -187,3 +194,31 @@ fetchFreeURL(url_t *u) free(u); } } + +int +fetchConnect(char *host, int port) +{ + struct sockaddr_in sin; + struct hostent *he; + int sd; + + /* look up host name */ + if ((he = gethostbyname(host)) == NULL) + return -1; + + /* set up socket address structure */ + bzero(&sin, sizeof(sin)); + bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length); + sin.sin_family = he->h_addrtype; + sin.sin_port = htons(port); + + /* try to connect */ + if ((sd = socket(sin.sin_family, SOCK_STREAM, 0)) < 0) + return -1; + if (connect(sd, (struct sockaddr *)&sin, sizeof sin) < 0) { + close(sd); + return -1; + } + + return sd; +} diff --git a/lib/libfetch/fetch.h b/lib/libfetch/fetch.h index 387d4c4..b536553 100644 --- a/lib/libfetch/fetch.h +++ b/lib/libfetch/fetch.h @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id$ + * $Id: fetch.h,v 1.1.1.1 1998/07/09 16:52:41 des Exp $ */ #ifndef _FETCH_H_INCLUDED @@ -46,7 +46,6 @@ struct url_s { char host[MAXHOSTNAMELEN+1]; char *doc; int port; - char *lasterr; }; typedef struct url_s url_t; @@ -56,7 +55,7 @@ FILE *fetchGetFile(url_t *, char *); FILE *fetchPutFile(url_t *, char *); /* HTTP-specific functions */ -char *fetchContentType(FILE *f); +char *fetchContentType(FILE *); FILE *fetchGetHTTP(url_t *, char *); FILE *fetchPutHTTP(url_t *, char *); @@ -65,10 +64,14 @@ FILE *fetchGetFTP(url_t *, char *); FILE *fetchPutFTP(url_t *, char *); /* Generic functions */ -url_t *fetchParseURL(char *URL); -void fetchFreeURL(url_t *u); +int fetchConnect(char *, int); +url_t *fetchParseURL(char *); +void fetchFreeURL(url_t *); FILE *fetchGetURL(char *, char *); FILE *fetchPutURL(char *, char *); +/* Error code and string */ +extern int fetchLastErrCode; +extern const char *fetchLastErrText; #endif diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c index 14d43b9..5df13ec 100644 --- a/lib/libfetch/ftp.c +++ b/lib/libfetch/ftp.c @@ -25,11 +25,11 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id$ + * $Id: ftp.c,v 1.1.1.1 1998/07/09 16:52:42 des Exp $ */ /* - * Portions of this code were taken from ftpio.c: + * Portions of this code were taken from or based on ftpio.c: * * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): @@ -58,80 +58,117 @@ #include #include #include +#include #include +#include #include #include +#include #include +#include #include "fetch.h" #include "ftperr.c" +#define FTP_DEFAULT_TO_ANONYMOUS #define FTP_ANONYMOUS_USER "ftp" #define FTP_ANONYMOUS_PASSWORD "ftp" +#define ENDL "\r\n" + static url_t cached_host; static FILE *cached_socket; -static int _ftp_errcode; -static int -_ftp_isconnected(url_t *url) +#ifndef NDEBUG +#define TRACE fprintf(stderr, "TRACE on line %d in " __FILE__ "\n", __LINE__); +#else +#define TRACE +#endif + +/* + * Map error code to string + */ +static const char * +_ftp_errstring(int e) { - return (cached_socket - && (strcmp(url->host, cached_host.host) == 0) - && (strcmp(url->user, cached_host.user) == 0) - && (strcmp(url->pwd, cached_host.pwd) == 0) - && (url->port == cached_host.port)); + struct ftperr *p = _ftp_errlist; + + while ((p->num != -1) && (p->num != e)) + p++; + + return p->string; +} + +/* + * Set error code + */ +static void +_ftp_seterr(int e) +{ + fetchLastErrCode = e; + fetchLastErrText = _ftp_errstring(e); +} + +/* + * Set error code according to errno + */ +static void +_ftp_syserr(void) +{ + fetchLastErrCode = errno; + fetchLastErrText = strerror(errno); } /* * Get server response, check that first digit is a '2' */ static int -_ftp_chkerr(FILE *s, char *e) +_ftp_chkerr(FILE *s, int *e) { char *line; size_t len; + TRACE; + + if (e) + *e = 0; + do { if (((line = fgetln(s, &len)) == NULL) || (len < 4)) + { + _ftp_syserr(); return -1; + } } while (line[3] == '-'); - if (!isdigit(line[0]) || !isdigit(line[1]) || !isdigit(line[2]) || (line[3] != ' ')) + if (!isdigit(line[1]) || !isdigit(line[1]) + || !isdigit(line[2]) || (line[3] != ' ')) { + _ftp_seterr(-1); return -1; + } - _ftp_errcode = (line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0'); + _ftp_seterr((line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0')); if (e) - *e = _ftp_errcode; + *e = fetchLastErrCode; return (line[0] == '2') - 1; } /* - * Map error code to string - */ -static const char * -_ftp_errstring(int e) -{ - struct ftperr *p = _ftp_errlist; - - while ((p->num) && (p->num != e)) - p++; - - return p->string; -} - -/* * Change remote working directory */ static int _ftp_cwd(FILE *s, char *dir) { + TRACE; + fprintf(s, "CWD %s\n", dir); - if (ferror(s)) + if (ferror(s)) { + _ftp_syserr(); return -1; + } return _ftp_chkerr(s, NULL); /* expecting 250 */ } @@ -139,112 +176,215 @@ _ftp_cwd(FILE *s, char *dir) * Retrieve file */ static FILE * -_ftp_retr(FILE *s, char *file, int pasv) +_ftp_retrieve(FILE *cf, char *file, int pasv) { char *p; + TRACE; + /* change directory */ if (((p = strrchr(file, '/')) != NULL) && (p != file)) { *p = 0; - if (_ftp_cwd(s, file) < 0) { + if (_ftp_cwd(cf, file) < 0) { *p = '/'; return NULL; } *p++ = '/'; } else { - if (_ftp_cwd(s, "/") < 0) + if (_ftp_cwd(cf, "/") < 0) return NULL; } /* retrieve file; p now points to file name */ + fprintf(stderr, "Arrrgh! No! No! I can't do it! Leave me alone!\n"); + return NULL; +} + +/* + * Store file + */ +static FILE * +_ftp_store(FILE *cf, char *file, int pasv) +{ + TRACE; + + cf = cf; + file = file; + pasv = pasv; + return NULL; +} + +/* + * Log on to FTP server + */ +static FILE * +_ftp_connect(char *host, int port, char *user, char *pwd) +{ + int sd, e; + FILE *f; + + TRACE; + + /* establish control connection */ + if ((sd = fetchConnect(host, port)) < 0) { + _ftp_syserr(); + return NULL; + } + if ((f = fdopen(sd, "r+")) == NULL) { + _ftp_syserr(); + goto ouch; + } + + /* expect welcome message */ + if (_ftp_chkerr(f, NULL) < 0) + goto fouch; + + /* send user name and password */ + fprintf(f, "USER %s" ENDL, user); + _ftp_chkerr(f, &e); + if (e == 331) { + /* server requested a password */ + fprintf(f, "PASS %s" ENDL, pwd); + _ftp_chkerr(f, &e); + } + if (e == 332) { + /* server requested an account */ + } + if (e != 230) /* won't let us near the WaReZ */ + goto fouch; + + /* might as well select mode and type at once */ +#ifdef FTP_FORCE_STREAM_MODE + fprintf(f, "MODE S" ENDL); + if (_ftp_chkerr(f, NULL) < 0) + goto ouch; +#endif + fprintf(f, "TYPE I" ENDL); + if (_ftp_chkerr(f, NULL) < 0) + goto ouch; + + /* done */ + return f; + +ouch: + close(sd); + return NULL; +fouch: + fclose(f); return NULL; } +/* + * Disconnect from server + */ +static void +_ftp_disconnect(FILE *f) +{ + TRACE; + + fprintf(f, "QUIT" ENDL); + _ftp_chkerr(f, NULL); + fclose(f); +} /* - * XXX rewrite these + * Check if we're already connected */ -#if 0 +static int +_ftp_isconnected(url_t *url) +{ + TRACE; + + return (cached_socket + && (strcmp(url->host, cached_host.host) == 0) + && (strcmp(url->user, cached_host.user) == 0) + && (strcmp(url->pwd, cached_host.pwd) == 0) + && (url->port == cached_host.port)); +} + FILE * fetchGetFTP(url_t *url, char *flags) { - int retcode = 0; - static FILE *fp = NULL; - static char *prev_host = NULL; - FILE *fp2; + FILE *cf = NULL; + int e; + TRACE; + #ifdef DEFAULT_TO_ANONYMOUS if (!url->user[0]) { strcpy(url->user, FTP_ANONYMOUS_USER); strcpy(url->pwd, FTP_ANONYMOUS_PASSWORD); } #endif + + /* set default port */ + if (!url->port) + url->port = 21; - if (fp && prev_host) { - if (!strcmp(prev_host, url->host)) { - /* Try to use cached connection */ - fp2 = ftpGet(fp, url->doc, NULL); - if (!fp2) { - /* Connection timed out or was no longer valid */ - fclose(fp); - free(prev_host); - prev_host = NULL; - } - else - return fp2; - } - else { - /* It's a different host now, flush old */ - fclose(fp); - free(prev_host); - prev_host = NULL; - } + /* try to use previously cached connection */ + if (_ftp_isconnected(url)) { + fprintf(cached_socket, "PWD" ENDL); + _ftp_chkerr(cached_socket, &e); + if (e > 0) + cf = cached_socket; } - fp = ftpLogin(url->host, url->user, url->pwd, url->port, 0, &retcode); - if (fp) { - if (strchr(flags, 'p')) { - if (ftpPassive(fp, 1) != SUCCESS) - /* XXX what should we do? */ ; - } - fp2 = ftpGet(fp, url->doc, NULL); - if (!fp2) { - /* Connection timed out or was no longer valid */ - retcode = ftpErrno(fp); - fclose(fp); - fp = NULL; - } - else - prev_host = strdup(url->host); - return fp2; + + /* connect to server */ + if (!cf) { + cf = _ftp_connect(url->host, url->port, url->user, url->pwd); + if (!cf) + return NULL; + if (cached_socket) + _ftp_disconnect(cached_socket); + cached_socket = cf; + memcpy(&cached_host, url, sizeof(url_t)); } - return NULL; + + /* initiate the transfer */ + return _ftp_retrieve(cf, url->doc, (flags && strchr(flags, 'p'))); } +/* + * Upload a file. + * Hmmm, that's almost an exact duplicate of the above... + */ FILE * fetchPutFTP(url_t *url, char *flags) { - static FILE *fp = NULL; - FILE *fp2; - int retcode = 0; + FILE *cf = NULL; + int e; + +#ifdef DEFAULT_TO_ANONYMOUS + if (!url->user[0]) { + strcpy(url->user, FTP_ANONYMOUS_USER); + strcpy(url->pwd, FTP_ANONYMOUS_PASSWORD); + } +#endif - if (fp) { /* Close previous managed connection */ - fclose(fp); - fp = NULL; + /* set default port */ + if (!url->port) + url->port = 21; + + /* try to use previously cached connection */ + if (_ftp_isconnected(url)) { + fprintf(cached_socket, "PWD" ENDL); + _ftp_chkerr(cached_socket, &e); + if (e > 0) + cf = cached_socket; } - fp = ftpLogin(url->host, url->user, url->pwd, url->port, 0, &retcode); - if (fp) { - if (strchr(flags, 'p')) { - if (ftpPassive(fp, 1) != SUCCESS) - /* XXX what should we do? */ ; - } - fp2 = ftpPut(fp, url->doc); - if (!fp2) { - retcode = ftpErrno(fp); - fclose(fp); - fp = NULL; - } - return fp2; + + /* connect to server */ + if (!cf) { + cf = _ftp_connect(url->host, url->port, url->user, url->pwd); + if (!cf) + return NULL; + if (cached_socket) + _ftp_disconnect(cached_socket); + cached_socket = cf; + memcpy(&cached_host, url, sizeof(url_t)); } - return NULL; + + + /* initiate the transfer */ + return _ftp_store(cf, url->doc, (flags && strchr(flags, 'p'))); } -#endif diff --git a/lib/libfetch/http.c b/lib/libfetch/http.c index 1cf9a9f..3178e2a 100644 --- a/lib/libfetch/http.c +++ b/lib/libfetch/http.c @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id$ + * $Id: http.c,v 1.1.1.1 1998/07/09 16:52:41 des Exp $ */ #include @@ -71,32 +71,15 @@ struct cookie unsigned b_len, chunksize; }; -static int -_http_connect(char *host, int port) +static const char * +_http_errstring(int e) { - struct sockaddr_in sin; - struct hostent *he; - int fd; - - /* look up host name */ - if ((he = gethostbyname(host)) == NULL) - return -1; + struct httperr *p = _http_errlist; - /* set up socket address structure */ - bzero(&sin, sizeof(sin)); - bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length); - sin.sin_family = he->h_addrtype; - sin.sin_port = htons(port); - - /* try to connect */ - if ((fd = socket(sin.sin_family, SOCK_STREAM, 0)) < 0) - return -1; - if (connect(fd, (struct sockaddr *)&sin, sizeof sin) < 0) { - close(fd); - return -1; - } - - return fd; + while ((p->num != -1) && (p->num != e)) + p++; + + return p->string; } static char * @@ -187,7 +170,7 @@ fetchContentType(FILE *f) FILE * fetchGetHTTP(url_t *URL, char *flags) { - int fd = -1, err, i, enc = ENC_NONE; + int sd = -1, err, i, enc = ENC_NONE; struct cookie *c; char *ln, *p, *q; FILE *f, *cf; @@ -222,17 +205,17 @@ fetchGetHTTP(url_t *URL, char *flags) host[len] = 0; /* connect */ - fd = _http_connect(host, port); + sd = fetchConnect(host, port); } /* if no proxy is configured or could be contacted, try direct */ - if (fd < 0) { - if ((fd = _http_connect(URL->host, URL->port)) < 0) + if (sd < 0) { + if ((sd = fetchConnect(URL->host, URL->port)) < 0) goto ouch; } /* reopen as stream */ - if ((f = fdopen(fd, "r+")) == NULL) + if ((f = fdopen(sd, "r+")) == NULL) goto ouch; c->real_f = f; @@ -270,8 +253,11 @@ fetchGetHTTP(url_t *URL, char *flags) DEBUG(fprintf(stderr, "code: [\033[1m%d\033[m]\n", err)); /* add code to handle redirects later */ - if (err != 200) + if (err != 200) { + fetchLastErrCode = err; + fetchLastErrText = _http_errstring(err); goto fouch; + } /* browse through header */ while (1) { @@ -320,8 +306,8 @@ fetchGetHTTP(url_t *URL, char *flags) return cf; ouch: - if (fd >= 0) - close(fd); + if (sd >= 0) + close(sd); free(c); return NULL; fouch: -- cgit v1.1