Initial Ccheckin of prozilla 2.0.4

This commit is contained in:
Mario Fetka
2010-08-31 03:50:41 +02:00
commit 093662fc48
226 changed files with 131185 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
#------------------------------------------------------------------------------
# Process this file with automake to produce Makefile.in.
#------------------------------------------------------------------------------
lib_LTLIBRARIES = libprozilla.la
libprozilla_la_SOURCES = \
common.h \
connect.c connect.h \
connection.c connection.h \
debug.c debug.h \
download.c download.h \
ftp.c ftp.h \
ftpparse.c ftpparse.h \
##getopt.c getopt.h \
main.c \
misc.c misc.h \
netrc.c netrc.h \
prozilla.h \
url.c url.h\
http.c http.h\
http-retr.c http-retr.h\
ftp-retr.c ftp-retr.h\
logfile.c logfile.h\
ftpsearch.c ftpsearch.h\
ping.c ping.h
# 0:0:0
# 0 -> interface version, changes whenever you change the API
# 0 -> changes whenever you make a revision of an interface no
# API changes...
# 0 -> changes whenever you change the API but keep it backwards
# compatible (have not removed a function from the API, for
# example...)
libprozilla_la_LDFLAGS = -version-info 1:0:1
includedir= $(prefix)/include/prozilla
include_HEADERS = prozilla.h common.h netrc.h
CPPFLAGS = @CPPFLAGS@ -DLOCALEDIR=\"$(datadir)/locale\"
INCLUDES = -I../intl -I@includedir@
#AM_CPPFLAGS = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
LIBS = @LIBS@ $(THREAD_LIBS)
AM_CFLAGS = @CFLAGS@ -D_REENTRANT -W -Wall -O2 -ggdb
#bin_PROGRAMS = testproz
#testproz_SOURCES = test.c
#testproz_LDADD = libprozilla.la

406
libprozilla/src/Makefile.in Normal file
View File

@@ -0,0 +1,406 @@
# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
#------------------------------------------------------------------------------
# Process this file with automake to produce Makefile.in.
#------------------------------------------------------------------------------
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
oldincludedir = /usr/include
DESTDIR =
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
host_alias = @host_alias@
host_triplet = @host@
AS = @AS@
BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@
CATALOGS = @CATALOGS@
CATOBJEXT = @CATOBJEXT@
CC = @CC@
DATADIRNAME = @DATADIRNAME@
DLLTOOL = @DLLTOOL@
GENCAT = @GENCAT@
GLIBC21 = @GLIBC21@
GMOFILES = @GMOFILES@
GMSGFMT = @GMSGFMT@
HAVE_LIB = @HAVE_LIB@
INSTOBJEXT = @INSTOBJEXT@
INTLBISON = @INTLBISON@
INTLLIBS = @INTLLIBS@
INTLOBJS = @INTLOBJS@
INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@
LIB = @LIB@
LIBICONV = @LIBICONV@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
LTLIB = @LTLIB@
MAKEINFO = @MAKEINFO@
MKINSTALLDIRS = @MKINSTALLDIRS@
MSGFMT = @MSGFMT@
MSGMERGE = @MSGMERGE@
OBJDUMP = @OBJDUMP@
PACKAGE = @PACKAGE@
POFILES = @POFILES@
POSUB = @POSUB@
RANLIB = @RANLIB@
THREAD_LIBS = @THREAD_LIBS@
USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
XGETTEXT = @XGETTEXT@
lib_LTLIBRARIES = libprozilla.la
libprozilla_la_SOURCES = common.h connect.c connect.h connection.c connection.h debug.c debug.h download.c download.h ftp.c ftp.h ftpparse.c ftpparse.h main.c misc.c misc.h netrc.c netrc.h prozilla.h url.c url.h http.c http.h http-retr.c http-retr.h ftp-retr.c ftp-retr.h logfile.c logfile.h ftpsearch.c ftpsearch.h ping.c ping.h
# 0:0:0
# 0 -> interface version, changes whenever you change the API
# 0 -> changes whenever you make a revision of an interface no
# API changes...
# 0 -> changes whenever you change the API but keep it backwards
# compatible (have not removed a function from the API, for
# example...)
libprozilla_la_LDFLAGS = -version-info 1:0:1
includedir = $(prefix)/include/prozilla
include_HEADERS = prozilla.h common.h netrc.h
CPPFLAGS = @CPPFLAGS@ -DLOCALEDIR=\"$(datadir)/locale\"
INCLUDES = -I../intl -I@includedir@
#AM_CPPFLAGS = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
LIBS = @LIBS@ $(THREAD_LIBS)
AM_CFLAGS = @CFLAGS@ -D_REENTRANT -W -Wall -O2 -ggdb
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h
CONFIG_CLEAN_FILES =
LTLIBRARIES = $(lib_LTLIBRARIES)
DEFS = @DEFS@ -I. -I$(srcdir) -I..
LDFLAGS = @LDFLAGS@
libprozilla_la_LIBADD =
libprozilla_la_OBJECTS = connect.lo connection.lo debug.lo download.lo \
ftp.lo ftpparse.lo main.lo misc.lo netrc.lo url.lo http.lo http-retr.lo \
ftp-retr.lo logfile.lo ftpsearch.lo ping.lo
CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
HEADERS = $(include_HEADERS)
DIST_COMMON = Makefile.am Makefile.in
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = tar
GZIP_ENV = --best
DEP_FILES = .deps/connect.P .deps/connection.P .deps/debug.P \
.deps/download.P .deps/ftp-retr.P .deps/ftp.P .deps/ftpparse.P \
.deps/ftpsearch.P .deps/http-retr.P .deps/http.P .deps/logfile.P \
.deps/main.P .deps/misc.P .deps/netrc.P .deps/ping.P .deps/url.P
SOURCES = $(libprozilla_la_SOURCES)
OBJECTS = $(libprozilla_la_OBJECTS)
all: all-redirect
.SUFFIXES:
.SUFFIXES: .S .c .lo .o .s
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES)
cd $(top_builddir) \
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
mostlyclean-libLTLIBRARIES:
clean-libLTLIBRARIES:
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
distclean-libLTLIBRARIES:
maintainer-clean-libLTLIBRARIES:
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(libdir)
@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
if test -f $$p; then \
echo "$(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p"; \
$(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p; \
else :; fi; \
done
uninstall-libLTLIBRARIES:
@$(NORMAL_UNINSTALL)
list='$(lib_LTLIBRARIES)'; for p in $$list; do \
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \
done
.s.o:
$(COMPILE) -c $<
.S.o:
$(COMPILE) -c $<
mostlyclean-compile:
-rm -f *.o core *.core
clean-compile:
distclean-compile:
-rm -f *.tab.c
maintainer-clean-compile:
.s.lo:
$(LIBTOOL) --mode=compile $(COMPILE) -c $<
.S.lo:
$(LIBTOOL) --mode=compile $(COMPILE) -c $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
distclean-libtool:
maintainer-clean-libtool:
libprozilla.la: $(libprozilla_la_OBJECTS) $(libprozilla_la_DEPENDENCIES)
$(LINK) -rpath $(libdir) $(libprozilla_la_LDFLAGS) $(libprozilla_la_OBJECTS) $(libprozilla_la_LIBADD) $(LIBS)
install-includeHEADERS: $(include_HEADERS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(includedir)
@list='$(include_HEADERS)'; for p in $$list; do \
if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \
echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p"; \
$(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p; \
done
uninstall-includeHEADERS:
@$(NORMAL_UNINSTALL)
list='$(include_HEADERS)'; for p in $$list; do \
rm -f $(DESTDIR)$(includedir)/$$p; \
done
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP)
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
here=`pwd` && cd $(srcdir) \
&& mkid -f$$here/ID $$unique $(LISP)
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS)'; \
unique=`for i in $$list; do echo $$i; done | \
awk ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
mostlyclean-tags:
clean-tags:
distclean-tags:
-rm -f TAGS ID
maintainer-clean-tags:
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
subdir = src
distdir: $(DISTFILES)
here=`cd $(top_builddir) && pwd`; \
top_distdir=`cd $(top_distdir) && pwd`; \
distdir=`cd $(distdir) && pwd`; \
cd $(top_srcdir) \
&& $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/Makefile
@for file in $(DISTFILES); do \
d=$(srcdir); \
if test -d $$d/$$file; then \
cp -pr $$d/$$file $(distdir)/$$file; \
else \
test -f $(distdir)/$$file \
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $$d/$$file $(distdir)/$$file || :; \
fi; \
done
DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
-include $(DEP_FILES)
mostlyclean-depend:
clean-depend:
distclean-depend:
-rm -rf .deps
maintainer-clean-depend:
%.o: %.c
@echo '$(COMPILE) -c $<'; \
$(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
@-cp .deps/$(*F).pp .deps/$(*F).P; \
tr ' ' '\012' < .deps/$(*F).pp \
| sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
>> .deps/$(*F).P; \
rm .deps/$(*F).pp
%.lo: %.c
@echo '$(LTCOMPILE) -c $<'; \
$(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
@-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \
< .deps/$(*F).pp > .deps/$(*F).P; \
tr ' ' '\012' < .deps/$(*F).pp \
| sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
>> .deps/$(*F).P; \
rm -f .deps/$(*F).pp
info-am:
info: info-am
dvi-am:
dvi: dvi-am
check-am: all-am
check: check-am
installcheck-am:
installcheck: installcheck-am
install-exec-am: install-libLTLIBRARIES
install-exec: install-exec-am
install-data-am: install-includeHEADERS
install-data: install-data-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
install: install-am
uninstall-am: uninstall-libLTLIBRARIES uninstall-includeHEADERS
uninstall: uninstall-am
all-am: Makefile $(LTLIBRARIES) $(HEADERS)
all-redirect: all-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
installdirs:
$(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir)
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
maintainer-clean-generic:
mostlyclean-am: mostlyclean-libLTLIBRARIES mostlyclean-compile \
mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
mostlyclean-generic
mostlyclean: mostlyclean-am
clean-am: clean-libLTLIBRARIES clean-compile clean-libtool clean-tags \
clean-depend clean-generic mostlyclean-am
clean: clean-am
distclean-am: distclean-libLTLIBRARIES distclean-compile \
distclean-libtool distclean-tags distclean-depend \
distclean-generic clean-am
-rm -f libtool
distclean: distclean-am
maintainer-clean-am: maintainer-clean-libLTLIBRARIES \
maintainer-clean-compile maintainer-clean-libtool \
maintainer-clean-tags maintainer-clean-depend \
maintainer-clean-generic distclean-am
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
maintainer-clean: maintainer-clean-am
.PHONY: mostlyclean-libLTLIBRARIES distclean-libLTLIBRARIES \
clean-libLTLIBRARIES maintainer-clean-libLTLIBRARIES \
uninstall-libLTLIBRARIES install-libLTLIBRARIES mostlyclean-compile \
distclean-compile clean-compile maintainer-clean-compile \
mostlyclean-libtool distclean-libtool clean-libtool \
maintainer-clean-libtool uninstall-includeHEADERS \
install-includeHEADERS tags mostlyclean-tags distclean-tags clean-tags \
maintainer-clean-tags distdir mostlyclean-depend distclean-depend \
clean-depend maintainer-clean-depend info-am info dvi-am dvi check \
check-am installcheck-am installcheck install-exec-am install-exec \
install-data-am install-data install-am install uninstall-am uninstall \
all-redirect all-am all installdirs mostlyclean-generic \
distclean-generic clean-generic maintainer-clean-generic clean \
mostlyclean distclean maintainer-clean
#bin_PROGRAMS = testproz
#testproz_SOURCES = test.c
#testproz_LDADD = libprozilla.la
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

181
libprozilla/src/common.h Normal file
View File

@@ -0,0 +1,181 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* Common #includes and #defines. */
/* $Id: common.h,v 1.7 2001/10/27 23:20:24 kalum Exp $ */
#ifndef COMMON_H
#define COMMON_H
#if HAVE_CONFIG_H
# include <config.h>
#endif
#if HAVE_STDIO_H
# include <stdio.h>
#endif
#if STDC_HEADERS
# if HAVE_STDLIB_H
# include <stdlib.h>
# endif
# include <stdarg.h>
#endif
#if HAVE_STRING_H
# if !STDC_HEADERS && HAVE_MEMORY_H
# include <memory.h>
# endif
# include <string.h>
#else
# if HAVE_STRINGS_H
# include <strings.h>
# endif
#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#if HAVE_CTYPE_H
# include <ctype.h>
#endif
#if HAVE_ERRNO_H
# include <errno.h>
#endif
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#if HAVE_FCNTL_H
# include <fcntl.h>
#endif
#if HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#if HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#include <netinet/in_systm.h>
#ifdef __FreeBSD__
#include <sys/param.h>
#include <sys/mount.h>
#else
#include <sys/vfs.h>
#endif
#if HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#if HAVE_NETDB_H
# include <netdb.h>
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#if HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#if HAVE_ASSERT_H
# include <assert.h>
#endif
#if HAVE_PWD_H
# include <pwd.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#if HAVE_PTHREAD_H
# include <pthread.h>
#endif
/* If we don't have vsnprintf() try to use __vsnprintf(). */
#if !defined(HAVE_VSNPRINTF) && defined(HAVE___VSNPRINTF)
# undef vsnprintf
# define vsnprintf __vsnprintf
# define HAVE_VSNPRINTF
#endif
/* If we don't have snprintf() try to use __snprintf(). */
#if !defined(HAVE_SNPRINTF) && defined(HAVE___SNPRINTF)
# undef snprintf
# define snprintf __snprintf
# define HAVE_SNPRINTF
#endif
typedef int boolean;
#ifndef FALSE
# define FALSE (0)
#endif
#ifndef TRUE
# define TRUE (!FALSE)
#endif
#ifndef NO
# define NO FALSE
#endif
#ifndef YES
# define YES TRUE
#endif
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
/* Gettext */
#include <libintl.h>
#define _(String) dgettext (PACKAGE, String)
#define gettext_noop(String) (String)
#ifndef HAVE_GNOME
#define N_(String) gettext_noop (String)
#endif
/* Gettext */
#endif /* COMMON_H */

306
libprozilla/src/connect.c Normal file
View File

@@ -0,0 +1,306 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* Connection routines. */
/* $Id: connect.c,v 1.24 2005/07/29 16:28:47 kalum Exp $ */
#include "common.h"
#include "misc.h"
#include "debug.h"
#include "connect.h"
/******************************************************************************
Connect to the specified server.
******************************************************************************/
uerr_t connect_to_server(int *sock, const char *name, int port,
struct timeval *tout)
{
int status, noblock, flags;
char szPort[10];
extern int h_errno;
int opt;
struct timeval timeout;
struct addrinfo hints, *res=NULL;
int error;
assert(name != NULL);
memcpy(&timeout, tout, sizeof(timeout));
memset(&hints, 0, sizeof(hints));
memset(szPort, 0, sizeof(szPort));
snprintf(szPort, sizeof(szPort), "%d", port);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(name, szPort, &hints, &res);
if (error) {
freeaddrinfo(res);
return HOSTERR;
}
/* Create a socket. */
if ((*sock = socket(res->ai_family, res->ai_socktype, IPPROTO_TCP)) < 1)
{
free(res);
return CONSOCKERR;
}
/* Experimental. */
flags = fcntl(*sock, F_GETFL, 0);
if (flags != -1)
noblock = fcntl(*sock, F_SETFL, flags | O_NONBLOCK);
else
noblock = -1;
status = connect(*sock, res->ai_addr, res->ai_addrlen);
if ((status == -1) && (noblock != -1) && (errno == EINPROGRESS))
{
fd_set writefd;
FD_ZERO(&writefd);
FD_SET(*sock, &writefd);
status = select((*sock + 1), NULL, &writefd, NULL, &timeout);
/* Do we need to retry if the err is EINTR? */
if (status > 0)
{
socklen_t arglen = sizeof(int);
if (getsockopt(*sock, SOL_SOCKET, SO_ERROR, &status, &arglen) < 0)
status = errno;
if (status != 0)
errno = status, status = -1;
if (errno == EINPROGRESS)
errno = ETIMEDOUT;
} else if (status == 0)
errno = ETIMEDOUT, status = -1;
}
if (status < 0)
{
close(*sock);
if (errno == ECONNREFUSED)
{
free(res);
return CONREFUSED;
} else
{
free(res);
return CONERROR;
}
} else
{
flags = fcntl(*sock, F_GETFL, 0);
if (flags != -1)
fcntl(*sock, F_SETFL, flags & ~O_NONBLOCK);
}
/* Enable KEEPALIVE, so dead connections could be closed
* earlier. Useful in conjuction with TCP kernel tuning
* in /proc/sys/net/ipv4/tcp_* files. */
opt = 1;
setsockopt(*sock, SOL_SOCKET, SO_KEEPALIVE,
(char *) &opt, (int) sizeof(opt));
free(res);
return NOCONERROR;
}
/******************************************************************************
...
******************************************************************************/
uerr_t bind_socket(int *sockfd)
{
struct sockaddr_in serv_addr;
/* Open a TCP socket (an Internet stream socket). */
if ((*sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
return CONSOCKERR;
/* Fill in the structure fields for binding. */
memset((void *) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(0); /* Let the system choose. */
/* Bind the address to the socket. */
if (bind(*sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
perror("bind");
close(*sockfd);
return BINDERR;
}
/* Allow only one server. */
if (listen(*sockfd, 1) < 0)
{
perror("listen");
close(*sockfd);
return LISTENERR;
}
return BINDOK;
}
/******************************************************************************
...
******************************************************************************/
int select_fd(int fd, struct timeval *timeout, int writep)
{
fd_set fds, exceptfds;
struct timeval to;
FD_ZERO(&fds);
FD_SET(fd, &fds);
FD_ZERO(&exceptfds);
FD_SET(fd, &exceptfds);
memcpy(&to, timeout, sizeof(struct timeval));
return (select(fd + 1, writep ? NULL : &fds, writep ? &fds : NULL,
&exceptfds, &to));
}
/******************************************************************************
Receive size bytes from sock with a time delay.
******************************************************************************/
int krecv(int sock, char *buffer, int size, int flags,
struct timeval *timeout)
{
int ret, arglen;
arglen = sizeof(int);
assert(size >= 0);
do
{
if (timeout)
{
do
{
ret = select_fd(sock, timeout, 0);
}
while ((ret == -1) && (errno == EINTR));
if (ret <= 0)
{
/* proz_debug("Error after select res=%d errno=%d.", ret, errno); */
/* Set errno to ETIMEDOUT on timeout. */
if (ret == 0)
errno = ETIMEDOUT;
return -1;
}
}
ret = recv(sock, buffer, size, flags);
}
while ((ret == -1) && (errno == EINTR));
return ret;
}
/******************************************************************************
Send size bytes to sock with a time delay.
******************************************************************************/
int ksend(int sock, char *buffer, int size, int flags,
struct timeval *timeout)
{
int ret = 0;
/* write() may write less than size bytes, thus the outward loop
keeps trying it until all was written, or an error occurred. The
inner loop is reserved for the usual EINTR f*kage, and the
innermost loop deals with the same during select(). */
while (size != 0)
{
do
{
if (timeout)
{
do
{
ret = select_fd(sock, timeout, 1);
}
while ((ret == -1) && (errno == EINTR));
if (ret <= 0)
{
/* Set errno to ETIMEDOUT on timeout. */
if (ret == 0)
errno = ETIMEDOUT;
return -1;
}
}
ret = send(sock, buffer, size, flags);
}
while ((ret == -1) && (errno == EINTR));
if (ret <= 0)
break;
buffer += ret;
size -= ret;
}
return ret;
}
/******************************************************************************
Accept a connection.
******************************************************************************/
uerr_t accept_connection(int listen_sock, int *data_sock)
{
struct sockaddr_in cli_addr;
socklen_t clilen = sizeof(cli_addr);
int sockfd;
sockfd = accept(listen_sock, (struct sockaddr *) &cli_addr, &clilen);
if (sockfd < 0)
{
perror("accept");
return ACCEPTERR;
}
*data_sock = sockfd;
/* Now we can free the listen socket since it is not needed...
accept() returned the new socket... */
close(listen_sock);
return ACCEPTOK;
}

53
libprozilla/src/connect.h Normal file
View File

@@ -0,0 +1,53 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* Connection routines. */
/* $Id: connect.h,v 1.17 2001/05/09 22:58:00 kalum Exp $ */
#ifndef CONNECT_H
#define CONNECT_H
#include "common.h"
#include "prozilla.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
uerr_t connect_to_server(int *sock, const char *name, int port,
struct timeval *timeout);
uerr_t bind_socket(int *sockfd);
int select_fd(int fd, struct timeval *timeout, int writep);
int krecv(int sock, char *buffer, int size, int flags,
struct timeval *timeout);
int ksend(int sock, char *buffer, int size, int flags,
struct timeval *timeout);
uerr_t accept_connection(int listen_sock, int *data_sock);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* CONNECT_H */

View File

@@ -0,0 +1,730 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* Several connection-related routines. */
/* $Id: connection.c,v 1.48 2005/09/19 16:18:02 kalum Exp $ */
#include "common.h"
#include "prozilla.h"
#include "connection.h"
#include "misc.h"
#include "connect.h"
#include "ftp.h"
#include "http.h"
#include "debug.h"
/******************************************************************************
...
******************************************************************************/
void init_response(connection_t * connection)
{
connection->serv_ret_lines = 0;
}
/******************************************************************************
This will free up the serv_ret_lines array if necessary, in order to prepare
it for the storage of the servers response.
******************************************************************************/
void done_with_response(connection_t * connection)
{
response_line *p, *p1;
/* Return if the array is not allocated. */
if (connection->serv_ret_lines == 0)
return;
p1 = connection->serv_ret_lines;
do
{
p = p1;
p1 = p->next;
kfree(p);
}
while (p1 != 0);
connection->serv_ret_lines = 0;
}
/******************************************************************************
Initialises the connection and sets it with values from the runtime struct.
******************************************************************************/
connection_t * proz_connection_init(urlinfo *url,pthread_mutex_t * mutex)
{
connection_t * connection=kmalloc(sizeof(connection_t));
memset(connection, 0, sizeof(connection_t));
/* memcpy(&connection->u, url, sizeof(urlinfo));*/
if(url)
memcpy(&connection->u,
proz_copy_url(url),
sizeof(urlinfo));
/* Copy the proxy structs. */
if (libprozrtinfo.ftp_proxy)
{
connection->ftp_proxy = kmalloc(sizeof(proxy_info));
memcpy(connection->ftp_proxy, libprozrtinfo.ftp_proxy,
sizeof(proxy_info));
/*
connection->use_ftp_proxy = libprozrtinfo.use_ftp_proxy;
*/
}
if (libprozrtinfo.http_proxy)
{
connection->http_proxy = kmalloc(sizeof(proxy_info));
memcpy(connection->http_proxy, libprozrtinfo.http_proxy,
sizeof(proxy_info));
/*
connection->use_http_proxy = libprozrtinfo.use_http_proxy;
*/
}
connection->use_netrc = libprozrtinfo.use_netrc;
connection->retry = TRUE;
connection->ftp_use_pasv = libprozrtinfo.ftp_use_pasv;
connection->http_no_cache = libprozrtinfo.http_no_cache;
connection->user_agent = strdup(DEFAULT_USER_AGENT);
connection->file_mode = strdup("wb");
/*NOTE: default of unlimited attempts */
connection->max_attempts = 0;
connection->attempts = 0;
/* Initialise all with default timeouts */
memcpy(&connection->xfer_timeout, &libprozrtinfo.conn_timeout,
sizeof(connection->xfer_timeout));
memcpy(&connection->ctrl_timeout, &libprozrtinfo.conn_timeout,
sizeof(connection->ctrl_timeout));
memcpy(&connection->conn_timeout, &libprozrtinfo.conn_timeout,
sizeof(connection->conn_timeout));
memcpy(&connection->retry_delay, &libprozrtinfo.conn_retry_delay,
sizeof(&connection->retry_delay));
connection->max_attempts = libprozrtinfo.max_attempts;
connection->rate_bps = 0;
/* Unlimited bandwith (0) */
connection->max_allowed_bps = 0;
pthread_cond_init(&connection->connecting_cond, NULL);
connection->status_change_mutex = mutex;
if (connection->status_change_mutex != 0)
{
pthread_mutex_init(connection->status_change_mutex, NULL);
}
pthread_mutex_init(&connection->access_mutex, NULL);
return connection;
}
/* Locks the connections mutex befoer chaging state. */
void connection_change_status(connection_t * connection, dl_status status)
{
if (connection->status_change_mutex != 0)
{
pthread_mutex_lock(connection->status_change_mutex);
connection->status = status;
pthread_mutex_unlock(connection->status_change_mutex);
}
}
/* this will open connection->localfile and read from connection->data_sock
(which should be already setup) till a EOF is reached or
the server closes the connection, in which case there is no way to know
whether we got the complete file.
*/
uerr_t connection_retr_fsize_not_known(connection_t * connection,
char *read_buffer,
int read_buffer_size)
{
off_t bytes_read;
connection_change_status(connection, DOWNLOADING);
gettimeofday(&connection->time_begin, NULL);
do
{
bytes_read =
krecv(connection->data_sock, read_buffer, read_buffer_size, 0,
&connection->xfer_timeout);
if (bytes_read > 0)
{
if (write_data_with_lock(connection, read_buffer, sizeof(char), bytes_read) < bytes_read)
{
proz_debug(_("write failed"));
connection_show_message(connection,
_
("Unable to write to file %s: %s!"),
connection->localfile, strerror(errno));
connection_change_status(connection, LOCALFATAL);
return FWRITEERR;
}
pthread_mutex_lock(&connection->access_mutex);
connection->remote_bytes_received += bytes_read;
pthread_mutex_unlock(&connection->access_mutex);
/*TODO: caclculate and throttle connections speed here */
/*DONE: */
connection_calc_ratebps(connection);
connection_throttle_bps(connection);
}
}
while (bytes_read > 0);
if (bytes_read == -1)
{
if (errno == ETIMEDOUT)
{
proz_debug(_("connection timed out"));
connection_change_status(connection, TIMEDOUT);
return READERR;
}
connection_change_status(connection, REMOTEFATAL);
return READERR;
}
connection_change_status(connection, COMPLETED);
connection_show_message(connection,
_("download for this connection completed"
"%s : %ld received"), connection->localfile,
connection->remote_bytes_received);
return FILEGETOK;
}
/* This will open connection->localfile and read from connection->data_sock
(which should be already setup) till the requested number of bytes are read.
Now since we explicitly know how much bytes to get we can do so, and is the server
closes the connection prematurely we know that has hapenned (because it hasn't supplied
the required number of bytes) and return a READERR.
*/
uerr_t connection_retr_fsize_known(connection_t * connection,
char *read_buffer, int read_buffer_size)
{
off_t bytes_read;
off_t bytes_to_get;
pthread_mutex_lock(&connection->access_mutex);
bytes_to_get = connection->remote_endpos - connection->remote_startpos;
pthread_mutex_unlock(&connection->access_mutex);
connection_change_status(connection, DOWNLOADING);
gettimeofday(&connection->time_begin, NULL);
while (bytes_to_get > 0)
{
bytes_read =
krecv(connection->data_sock, read_buffer,
bytes_to_get >
read_buffer_size ? read_buffer_size : bytes_to_get, 0,
&connection->xfer_timeout);
if (bytes_read == 0 && bytes_to_get > 0)
{
connection_show_message(connection,
_("Server Closed Connection Prematurely!"));
connection_change_status(connection, REMOTEFATAL);
return READERR;
}
if (bytes_read == -1)
{
if (errno == ETIMEDOUT)
{
proz_debug(_("connection timed out"));
connection_change_status(connection, TIMEDOUT);
return READERR;
}
connection_change_status(connection, REMOTEFATAL);
return READERR;
}
bytes_to_get -= bytes_read;
if (bytes_read > 0)
{
if (write_data_with_lock(connection, read_buffer, sizeof(char), bytes_read) < bytes_read)
{
proz_debug(_("write failed"));
connection_show_message(connection,
_
("Unable to write to file %s: %s!"),
connection->localfile, strerror(errno));
connection_change_status(connection, LOCALFATAL);
return FWRITEERR;
}
pthread_mutex_lock(&connection->access_mutex);
connection->remote_bytes_received += bytes_read;
pthread_mutex_unlock(&connection->access_mutex);
/*TODO: caclculate and throttle connections speed here */
/*DONE: */
connection_calc_ratebps(connection);
connection_throttle_bps(connection);
}
}
connection_change_status(connection, COMPLETED);
connection_show_message(connection,
_("download for this connection completed"
"%s : %ld received"), connection->localfile,
connection->remote_bytes_received);
return FILEGETOK;
}
/* This function modifies a single connections download start and
end info it returns 1 on sucess and -1 on error.
*/
int connection_load_resume_info(connection_t * connection)
{
if(connection->remote_startpos-connection->orig_remote_startpos!=connection->remote_bytes_received)
{
proz_debug("connection->remote start pos before loading %ld", connection->remote_startpos);
//connection->remote_startpos +=connection->remote_bytes_received;
connection->remote_startpos +=(connection->remote_bytes_received-(connection->remote_startpos-connection->orig_remote_startpos));
proz_debug("connection->remote start pos after loading %ld", connection->remote_startpos);
}
return 1;
}
dl_status proz_connection_get_status(connection_t * connection)
{
dl_status status;
pthread_mutex_lock(connection->status_change_mutex);
status = connection->status;
pthread_mutex_unlock(connection->status_change_mutex);
return status;
}
/*This will return a textual representation of the status of a conenction. */
char *proz_connection_get_status_string(connection_t * connection)
{
dl_status status;
pthread_mutex_lock(connection->status_change_mutex);
status = connection->status;
pthread_mutex_unlock(connection->status_change_mutex);
switch (connection->status)
{
case IDLE:
return (_("Idle"));
case CONNECTING:
return (_("Connecting"));
case LOGGININ:
return (_("Logging in"));
case DOWNLOADING:
return (_("Downloading"));
break;
case COMPLETED:
return (_("Completed"));
case LOGINFAIL:
return (_("Login Denied"));
case CONREJECT:
return (_("Connect Refused"));
case REMOTEFATAL:
return (_("Remote Fatal"));
case LOCALFATAL:
return (_("Local Fatal"));
case TIMEDOUT:
return (_("Timed Out"));
case MAXTRYS:
return (_("Max attempts reached"));
default:
return (_("Unkown Status!"));
}
}
pthread_mutex_t connection_msg_mutex = PTHREAD_MUTEX_INITIALIZER;
/*calls the msg_proc function if not null */
void connection_show_message(connection_t * connection, const char *format,
...)
{
va_list args;
char message[MAX_MSG_SIZE + 1];
pthread_mutex_lock(&connection_msg_mutex);
va_start(args, format);
vsnprintf(message, MAX_MSG_SIZE, format, args);
va_end(args);
if (connection->msg_proc)
connection->msg_proc(message, connection->cb_data);
/*FIXME: Remove this later */
// printf("%s\n", message);
pthread_mutex_unlock(&connection_msg_mutex);
}
/* Returns the total number of bytes that have been saved to the file*/
off_t proz_connection_get_total_bytes_got(connection_t * connection)
{
off_t ret;
pthread_mutex_lock(&connection->access_mutex);
ret = connection->remote_bytes_received;
pthread_mutex_unlock(&connection->access_mutex);
return ret;
}
/*****************************************************************************
Returns the total number of bytes that has being got from the server
by this connection.
******************************************************************************/
off_t proz_connection_get_total_remote_bytes_got(connection_t * connection)
{
off_t ret;
pthread_mutex_lock(&connection->access_mutex);
ret = (connection->remote_bytes_received
- (connection->remote_startpos-connection->orig_remote_startpos));
pthread_mutex_unlock(&connection->access_mutex);
//proz_debug("CONNECTION TOTAL REMOTE BYTES GOT =%lld", ret);
return ret;
}
void proz_get_url_info_loop(connection_t * connection, pthread_t *thread)
{
assert(connection);
assert(thread);
connection->running = TRUE;
pthread_create(thread, NULL,
(void *(*)(void *)) get_url_info_loop,
(void *) connection);
}
/************************************************************************
This Fucntion will retreive info about the given url in the connection,
handling conditions like redirection from http to ftp etc
*************************************************************************/
void get_url_info_loop(connection_t * connection)
{
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
/*TODO Should we try to make it broadcast a condition to the other threads? */
pthread_mutex_lock(&connection->access_mutex);
connection->running = TRUE;
pthread_mutex_unlock(&connection->access_mutex);
do
{
switch (connection->u.proto)
{
case URLHTTP:
connection->err = http_get_url_info_loop(connection);
break;
case URLFTP:
connection->err = ftp_get_url_info_loop(connection);
break;
default:
proz_die(_("Error: unsupported protocol"));
}
if (connection->err == NEWLOCATION)
{
char *constructed_newloc;
char *referer;
referer=kstrdup(connection->u.url);
/*DONE : handle relative urls too */
constructed_newloc =
uri_merge(connection->u.url, connection->hs.newloc);
proz_debug("Redirected to %s, merged URL = %s",
connection->hs.newloc, constructed_newloc);
proz_free_url(&connection->u, 0);
connection->err =
proz_parse_url(constructed_newloc, &connection->u, 0);
if (connection->err != URLOK)
{
connection_show_message(connection,
_
("The server returned location is wrong: %s!"),
constructed_newloc);
pthread_mutex_lock(&connection->access_mutex);
connection->running = FALSE;
pthread_mutex_unlock(&connection->access_mutex);
kfree(constructed_newloc);
connection->err = HERR;
return;
} else
connection_show_message(connection, _("Redirected to => %s"),
constructed_newloc);
connection->u.referer=referer;
kfree(constructed_newloc);
connection->err = NEWLOCATION;
}
}
while (connection->err == NEWLOCATION);
return;
}
void proz_connection_set_msg_proc(connection_t * connection,
message_proc msg_proc, void *cb_data)
{
assert(connection != NULL);
connection->msg_proc = msg_proc;
connection->cb_data = cb_data;
}
void connection_calc_ratebps(connection_t * connection)
{
struct timeval tv_cur;
struct timeval tv_diff;
float diff_us;
pthread_mutex_lock(&connection->access_mutex);
if (connection->time_begin.tv_sec == 0
&& connection->time_begin.tv_usec == 0)
{
connection->rate_bps = 0;
pthread_mutex_unlock(&connection->access_mutex);
return;
} else
{
gettimeofday(&tv_cur, NULL);
proz_timeval_subtract(&tv_diff, &tv_cur, &(connection->time_begin));
diff_us = ((float) tv_diff.tv_sec * 10e5) + tv_diff.tv_usec;
/* if (diff_us == 0) */
/* { */
/* pthread_mutex_unlock(&connection->access_mutex); */
/* return; */
/* } */
/* connection->rate_bps = */
/* ((float) (connection->remote_bytes_received */
/* - (connection->remote_startpos-connection->orig_remote_startpos)) * 10e5 / diff_us); */
/* } */
if (diff_us <100000)
{
connection->rate_bps = 0;
pthread_mutex_unlock(&connection->access_mutex);
return;
}
else
connection->rate_bps =
((float) (connection->remote_bytes_received
- (connection->remote_startpos-connection->orig_remote_startpos)) * 10e5 / diff_us);
}
pthread_mutex_unlock(&connection->access_mutex);
return;
}
void connection_throttle_bps(connection_t * connection)
{
struct timeval tv_cur;
struct timeval tv_diff;
float diff_us;
float wtime;
struct timeval tv_delay;
float con_timeout_usecs;
pthread_mutex_lock(&connection->access_mutex);
con_timeout_usecs =
(connection->conn_timeout.tv_sec * 10e5) +
connection->conn_timeout.tv_usec;
if (connection->rate_bps == 0 || connection->max_allowed_bps == 0)
{
pthread_mutex_unlock(&connection->access_mutex);
return;
}
if (connection->time_begin.tv_sec == 0
&& connection->time_begin.tv_usec == 0)
{
pthread_mutex_unlock(&connection->access_mutex);
return;
}
gettimeofday(&tv_cur, NULL);
proz_timeval_subtract(&tv_diff, &tv_cur, &(connection->time_begin));
diff_us = ((float) tv_diff.tv_sec * 10e5) + tv_diff.tv_usec;
if (diff_us == 0)
{
pthread_mutex_unlock(&connection->access_mutex);
return;
}
wtime =
10e5 * (connection->remote_bytes_received
- (connection->remote_startpos-connection->orig_remote_startpos)) /
connection->max_allowed_bps;
pthread_mutex_unlock(&connection->access_mutex);
memset(&tv_delay, 0, sizeof(tv_delay));
if (wtime > diff_us)
{
/*too fast have to delay */
// proz_debug("wtime %f, diff_us %f", wtime, diff_us);
if ((wtime - diff_us) > con_timeout_usecs) /* problem here */
{
/*If we were to delay for wtime-diff_us we would cause a connection
timeout, so rather than doing that shall we delay for a bit lesser
than the time for the timeout, like say 1 second less
*/
const int limit_time_us = 2 * 10e5;
/* Will the connection timeout - limit_time_us be less or equal to 0?
If so no point in delaing beacuse the connection wold timeout
*/
if ((con_timeout_usecs - limit_time_us) <= 0)
{
proz_debug
("Cant throttle: Connection would timeout if done so, please try increasing the timeout value");
return;
}
tv_delay.tv_usec = con_timeout_usecs - limit_time_us;
/* message
("Cant throttle fully : Connection would timeout if done so, please try increasing the timeout value"); */
proz_debug("delaymaxlimit %ld sec\n", tv_delay.tv_usec);
} else
{
tv_delay.tv_usec = (wtime - diff_us);
//#warning "comment out the following line before releasing the code base"
proz_debug("sleeping %f secs\n", (wtime - diff_us) / 10e5);
}
tv_delay.tv_sec = tv_delay.tv_usec / 1000000;
tv_delay.tv_usec = tv_delay.tv_usec % 1000000;
if (select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv_delay) < 0)
{
proz_debug("Unable to throttle Bandwith\n");
}
}
}
boolean proz_connection_running(connection_t * connection)
{
boolean running;
pthread_mutex_lock(&connection->access_mutex);
running = connection->running;
pthread_mutex_unlock(&connection->access_mutex);
return running;
}
void proz_connection_set_url(connection_t * connection, urlinfo *url)
{
assert(url);
memcpy(&connection->u,
proz_copy_url(url),
sizeof(urlinfo));
}
void proz_connection_free_connection(connection_t * connection,
boolean complete)
{
assert(connection);
/*TODO what about szBuffer..also have to free the URL u */
if (connection->localfile)
kfree(connection->localfile);
if (connection->file_mode)
kfree(connection->file_mode);
if (connection->http_proxy)
kfree(connection->http_proxy);
if (connection->ftp_proxy)
kfree(connection->ftp_proxy);
if (connection->user_agent)
kfree(connection->user_agent);
/* free the serv_ret_lines array */
if (connection->serv_ret_lines != 0)
{
done_with_response(connection);
}
if (complete == TRUE)
kfree(connection);
}
size_t write_data_with_lock(connection_t * connection, const void *ptr, size_t size, size_t nmemb)
{
size_t ret;
flockfile(connection->fp);
/*Seek appropriately......*/
ret=fseeko(connection->fp, connection->local_startpos+connection->remote_bytes_received, SEEK_SET);
ret=fwrite( ptr, size, nmemb, connection->fp);
funlockfile(connection->fp);
return ret;
}

View File

@@ -0,0 +1,63 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* Several connection-related routines. */
/* $Id: connection.h,v 1.34 2005/01/11 01:49:11 sean Exp $ */
#ifndef CONNECTION_H
#define CONNECTION_H
#include "common.h"
#include "prozilla.h"
#include "url.h"
#ifdef __cplusplus
extern "C" {
#endif
void init_response(connection_t * connection);
void done_with_response(connection_t * connection);
void connection_change_status(connection_t * connection,
dl_status status);
uerr_t connection_retr_fsize_not_known(connection_t * connection,
char *read_buffer,
int read_buffer_size);
uerr_t connection_retr_fsize_known(connection_t * connection,
char *read_buffer,
int read_buffer_size);
int connection_load_resume_info(connection_t * connection);
void connection_show_message(connection_t * connection,
const char *format, ...);
void connection_calc_ratebps(connection_t * connection);
void connection_throttle_bps(connection_t * connection);
void get_url_info_loop(connection_t * connection);
size_t write_data_with_lock(connection_t *connection, const void *ptr, size_t size, size_t nmemb);
#ifdef __cplusplus
}
#endif
#endif /* CONNECTION_H */

113
libprozilla/src/debug.c Normal file
View File

@@ -0,0 +1,113 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* Debugging routines. */
/* $Id: debug.c,v 1.20 2001/08/17 21:53:39 kalum Exp $ */
#include "common.h"
#include "misc.h"
#include "prozilla.h"
#include "debug.h"
static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
/******************************************************************************
Initialises the debug system, deletes any prior debug.log file if present
******************************************************************************/
void debug_init()
{
proz_debug_delete_log();
return;
}
void proz_debug_delete_log()
{
char logfile_name[PATH_MAX];
snprintf(logfile_name, PATH_MAX, "%s/debug.log", libprozrtinfo.log_dir);
if (unlink(logfile_name) == -1)
{
/*
* if the file is not present the continue silently
*/
if (errno == ENOENT)
return;
else
{
proz_debug(_("unable to delete the file %s. Reason-: %s"),
strerror(errno));
}
}
}
/******************************************************************************
Write a message to the debug-file.
******************************************************************************/
void proz_debug(const char *format, ...)
{
FILE *fp;
va_list args;
char message[MAX_MSG_SIZE + 1 + 1];
char logfile_name[PATH_MAX];
snprintf(logfile_name, PATH_MAX, "%s/debug.log", libprozrtinfo.log_dir);
pthread_mutex_lock(&debug_mutex);
if (libprozrtinfo.debug_mode == TRUE)
{
va_start(args, format);
vsnprintf((char *) &message, MAX_MSG_SIZE, format, args);
va_end(args);
/* Remove all newlines from the end of the string. */
while ((message[strlen(message) - 1] == '\r')
|| (message[strlen(message) - 1] == '\n'))
message[strlen(message) - 1] = '\0';
/* Append a newline. */
message[strlen(message) + 1] = '\0';
message[strlen(message)] = '\n';
if (!(fp = fopen(logfile_name, "at")))
{
pthread_mutex_unlock(&debug_mutex);
return;
}
if (fwrite(message, 1, strlen(message), fp) != strlen(message))
{
pthread_mutex_unlock(&debug_mutex);
fclose(fp);
return;
}
fclose(fp);
}
pthread_mutex_unlock(&debug_mutex);
}

33
libprozilla/src/debug.h Normal file
View File

@@ -0,0 +1,33 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* Debugging routines. */
/* $Id: debug.h,v 1.14 2001/07/11 23:19:41 kalum Exp $ */
#ifndef DEBUG_H
#define DEBUG_H
#include "common.h"
void debug_init();
#endif /* DEBUG_H */

2169
libprozilla/src/download.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,51 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* Download routines. */
/* $Id: download.h,v 1.25 2001/09/30 23:13:50 kalum Exp $ */
#ifndef DOWNLOAD_H
#define DOWNLOAD_H
#include "common.h"
#include "prozilla.h"
#include "connection.h"
#ifdef __cplusplus
extern "C" {
#endif
void download_show_message(download_t * download, const char *format,
...);
int download_query_conns_status_count(download_t * download,
dl_status status, char *server);
void download_join_downloads(download_t * download);
void join_downloads(download_t * download);
void download_calc_throttle_factor(download_t * download);
uerr_t download_handle_threads_ftpsearch(download_t * download);
uerr_t download_handle_threads_no_ftpsearch(download_t * download);
#ifdef __cplusplus
}
#endif
#endif /* DOWNLOAD_H */

338
libprozilla/src/ftp-retr.c Normal file
View File

@@ -0,0 +1,338 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* $Id: ftp-retr.c,v 1.18 2005/01/11 01:49:11 sean Exp $ */
#include "common.h"
#include "prozilla.h"
#include "connect.h"
#include "misc.h"
#include "url.h"
#include "netrc.h"
#include "debug.h"
#include "ftp.h"
#include "ftp-retr.h"
/* Will download a portion of/or the full file from the connection->url.
*/
uerr_t proz_ftp_get_file(connection_t * connection)
{
uerr_t err;
char *user, *passwd;
netrc_entry *netrc_ent;
boolean passive_mode;
char buffer[HTTP_BUFFER_SIZE];
/* we want it to terminate immediately */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
assert(connection->localfile != NULL);
assert(connection->file_mode != NULL);
/*clear the socks */
connection->ctrl_sock = 0;
connection->data_sock = 0;
connection->listen_sock = 0;
/* if there is nothing to download then return */
if (connection->status == COMPLETED)
{
gettimeofday(&connection->time_begin, NULL);
return FTPOK;
}
init_response(connection);
pthread_mutex_lock(connection->status_change_mutex);
connection->status = CONNECTING;
/* connection_change_status(connection, CONNECTING); */
pthread_cond_broadcast(&connection->connecting_cond);
pthread_mutex_unlock(connection->status_change_mutex);
/* if we have to use a HTTP proxy call the routine which is defined in http-retr.c and just return.
*/
if (ftp_use_proxy(connection)
&& connection->ftp_proxy->type == HTTPPROXY)
{
err = ftp_get_file_from_http_proxy(connection);
return err;
}
if (ftp_use_proxy(connection))
{
/* Connect to the proxy server here. */
err = ftp_connect_to_server(connection,
connection->ftp_proxy->proxy_url.host,
connection->ftp_proxy->proxy_url.port);
} else
{
err = ftp_connect_to_server(connection, connection->u.host,
connection->u.port);
}
if (err == FTPCONREFUSED)
{
connection_change_status(connection, CONREJECT);
close_sock(&connection->ctrl_sock);
return err;
}
if (err != FTPOK)
{
connection_change_status(connection, REMOTEFATAL);
return err;
}
done_with_response(connection);
user = connection->u.user;
passwd = connection->u.passwd;
/* Use .netrc if asked to do so. */
if (connection->use_netrc == TRUE)
{
netrc_ent = search_netrc(libprozrtinfo.netrc_list, connection->u.host);
if (netrc_ent != NULL)
{
user = netrc_ent->account;
passwd = netrc_ent->password;
}
}
user = user ? user : libprozrtinfo.ftp_default_user;
passwd = passwd ? passwd : libprozrtinfo.ftp_default_passwd;
proz_debug(_("Logging in as user %s with password %s."), user, passwd);
connection_change_status(connection, LOGGININ);
init_response(connection);
err = ftp_login(connection, user, passwd);
if (err != FTPOK)
{
if (err == FTPLOGREFUSED)
{
connection_change_status(connection, LOGINFAIL);
} else
{
connection_change_status(connection, REMOTEFATAL);
}
close_sock(&connection->ctrl_sock);
return err;
}
done_with_response(connection);
init_response(connection);
err = ftp_binary(connection);
if (err != FTPOK)
{
connection_change_status(connection, REMOTEFATAL);
close_sock(&connection->ctrl_sock);
return err;
}
done_with_response(connection);
/* Do we need to CWD? */
if (*connection->u.dir)
{
init_response(connection);
err = ftp_cwd(connection, connection->u.dir);
if (err != FTPOK)
{
connection_change_status(connection, REMOTEFATAL);
proz_debug(_("CWD failed to change to directory '%s'."),
connection->u.dir);
close_sock(&connection->ctrl_sock);
return err;
} else
{
proz_debug(_("CWD ok."));
done_with_response(connection);
}
} else
proz_debug(_("CWD not needed."));
err = ftp_setup_data_sock_1(connection, &passive_mode);
if (err != FTPOK)
{
connection_change_status(connection, REMOTEFATAL);
close_sock(&connection->ctrl_sock);
return err;
}
/* do we need to REST */
if (connection->remote_startpos > 0
&& connection->resume_support == TRUE)
{
err = ftp_rest(connection, connection->remote_startpos);
}
if (err != FTPOK)
{
if (err == FTPRESTFAIL)
proz_debug
(_
("I have a bug in my code!!, check remote_starpos and resume_support values"));
connection_change_status(connection, REMOTEFATAL);
close_sock(&connection->ctrl_sock);
return err;
}
err = ftp_retr(connection, connection->u.file);
if (err != FTPOK)
{
proz_debug(_("RETR failed"));
close_sock(&connection->ctrl_sock);
connection_change_status(connection, REMOTEFATAL);
return err;
}
err = ftp_setup_data_sock_2(connection, &passive_mode);
if (err != FTPOK)
{
return err;
}
/* which routine to call */
if (connection->main_file_size == -1)
err =
connection_retr_fsize_not_known(connection, buffer,
sizeof(buffer));
else
err = connection_retr_fsize_known(connection, buffer, sizeof(buffer));
close_sock(&connection->data_sock);
close_sock(&connection->ctrl_sock);
if (err == FILEGETOK)
return FTPOK;
else
return err;
}
/* A genuine loop ;) It willed be called by the main thread, and
this will handle all possible errors itself, retrying until the number
of maximum tries for the connection is realised or a error occurs which
needs to be passed upwards for handling, such as LOGINFAIL
*/
uerr_t ftp_loop(connection_t * connection)
{
boolean retrying_from_loop = FALSE;
assert(connection->max_attempts >= 0);
assert(connection->attempts >= 0);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
do
{
if (connection->attempts > 0)
{
if (retrying_from_loop == TRUE)
{
connection_show_message(connection,
_("Retrying..Attempt %d in %d seconds"),
connection->attempts,
connection->retry_delay.tv_sec);
delay_ms(connection->retry_delay.tv_sec * 1000);
}
if (connection->resume_support == TRUE)
{
if (connection_load_resume_info(connection) == -1)
{
connection_show_message(connection,
_
("Error while attemting to process download file "));
}
} else
{
/*If we cant resume then reset the connections bytesreceived to 0 */
connection->remote_bytes_received = 0;
}
}
/*Push the handler which will cleanup any sockets that are left open */
pthread_cleanup_push(cleanup_socks, (void *) connection);
connection->err = proz_ftp_get_file(connection);
/*pop the handler */
pthread_cleanup_pop(0);
connection->attempts++;
/*Should the error be handled at this level ? */
if (!ftp_loop_handle_error(connection->err))
{
return connection->err; /*If not return and the main thread will handle it */
}
switch (connection->err)
{
case FTPOK:
connection_show_message(connection, _("Successfully got download"));
return connection->err;
break;
default:
connection_show_message(connection,
_("Error occured in connection..."));
break;
}
retrying_from_loop = TRUE;
}
while ((connection->attempts < connection->max_attempts)
|| connection->max_attempts == 0);
connection_show_message(connection,
_
("I have tried %d attempt(s) and have failed, aborting"),
connection->attempts);
return connection->err;
}
/*Return true if it is a error which can be handled within the ftp_loop,
or false if it should be passed upwards so that the main download thread can
restart it when necessary after processing other threads status too */
boolean ftp_loop_handle_error(uerr_t err)
{
proz_debug("Error encountered in ftp_loop is %d", err);
if (err == FTPNSFOD || err == FTPLOGREFUSED || err == FTPCONREFUSED
|| err == FWRITEERR || err == FOPENERR || err == FTPCWDFAIL
|| err == FTPRESTFAIL)
return FALSE;
else
return TRUE;
}

View File

@@ -0,0 +1,40 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* $Id: ftp-retr.h,v 1.6 2001/06/25 12:30:55 kalum Exp $ */
#ifndef FTP_RETR_H
#define FTP_RETR_H
#include "common.h"
#include "connection.h"
#ifdef __cplusplus
extern "C" {
#endif
uerr_t proz_ftp_get_file(connection_t * connection);
uerr_t ftp_loop(connection_t * connection);
boolean ftp_loop_handle_error(uerr_t err);
uerr_t ftp_get_file_from_http_proxy(connection_t * connection);
#ifdef __cplusplus
}
#endif
#endif /* FTP_RETR_H */

1257
libprozilla/src/ftp.c Normal file

File diff suppressed because it is too large Load Diff

77
libprozilla/src/ftp.h Normal file
View File

@@ -0,0 +1,77 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* FTP support. */
/* $Id: ftp.h,v 1.35 2005/09/04 00:06:50 kalum Exp $ */
#ifndef FTP_H
#define FTP_H
#include "common.h"
#include "url.h"
#include "connection.h"
#ifdef __cplusplus
extern "C" {
#endif
int ftp_check_msg(connection_t * connection, int len);
int ftp_read_msg(connection_t * connection, int len);
uerr_t ftp_send_msg(connection_t * connection, const char *format, ...);
uerr_t ftp_get_line(connection_t * connection, char *line);
uerr_t ftp_ascii(connection_t * connection);
uerr_t ftp_binary(connection_t * connection);
uerr_t ftp_port(connection_t * connection, const char *command);
uerr_t ftp_list(connection_t * connection, const char *file);
uerr_t ftp_retr(connection_t * connection, const char *file);
uerr_t ftp_pasv(connection_t * connection, unsigned char *addr);
uerr_t ftp_rest(connection_t * connection, off_t bytes);
uerr_t ftp_cwd(connection_t * connection, const char *dir);
uerr_t ftp_pwd(connection_t * connection, char *dir);
uerr_t ftp_size(connection_t * connection, const char *file, off_t *size);
uerr_t ftp_connect_to_server(connection_t * connection, const char *name,
int port);
uerr_t ftp_get_listen_socket(connection_t * connection,
int *listen_sock);
uerr_t ftp_login(connection_t * connection, const char *username,
const char *passwd);
boolean ftp_use_proxy(connection_t * connection);
uerr_t proz_ftp_get_url_info(connection_t * connection);
uerr_t ftp_setup_data_sock_1(connection_t * connection,
boolean * passive_mode);
uerr_t ftp_setup_data_sock_2(connection_t * connection,
boolean * passive_mode);
uerr_t ftp_get_url_info_loop(connection_t * connection);
uerr_t ftp_get_url_info_from_http_proxy(connection_t * connection);
#ifdef __cplusplus
}
#endif
#endif /* FTP_H */

225
libprozilla/src/ftpparse.c Normal file
View File

@@ -0,0 +1,225 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
//Rewrite of the ftp parsing code as we needed to extract the date of
//the file to save it when the downloading is complete.
#include "common.h"
#include "ftpparse.h"
#include "prozilla.h"
/* MultiNet (some spaces removed from examples) */
/* "00README.TXT;1 2 30-DEC-1996 17:44 [SYSTEM] (RWED,RWED,RE,RE)" */
/* "CORE.DIR;1 1 8-SEP-1996 16:09 [SYSTEM] (RWE,RWE,RE,RE)" */
/* and non-MutliNet VMS: */
/* "CII-MANUAL.TEX;1 213/216 29-JAN-1996 03:33:12 [ANONYMOU,ANONYMOUS] (RWED,RWED,,)" */
/* MSDOS format */
/* 04-27-00 09:09PM <DIR> licensed */
/* 07-18-00 10:16AM <DIR> pub */
/* 04-14-00 03:47PM 589 readme.htm */
long getlong(char *buf,int len)
{
long u = 0;
while (len-- > 0)
u = u * 10 + (*buf++ - '0');
return u;
}
/* Find next Field
** ---------------
** Finds the next RFC822 token in a string
** On entry,
** *pstr points to a string containing a word separated
** by white white space "," ";" or "=". The word
** can optionally be quoted using <"> or "<" ">"
** Comments surrrounded by '(' ')' are filtered out
**
** On exit,
** *pstr has been moved to the first delimiter past the
** field
** THE STRING HAS BEEN MUTILATED by a 0 terminator
**
** Returns a pointer to the first word or NULL on error
*/
char * get_nextfield (char ** pstr)
{
char * p = *pstr;
char * start = NULL;
if (!pstr || !*pstr) return NULL;
while (1) {
/* Strip white space and other delimiters */
while (*p && (isspace((int) *p) || *p==',' || *p==';' || *p=='=')) p++;
if (!*p) {
*pstr = p;
return NULL; /* No field */
}
if (*p == '"') { /* quoted field */
start = ++p;
for(;*p && *p!='"'; p++)
if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
break; /* kr95-10-9: needs to stop here */
} else if (*p == '<') { /* quoted field */
start = ++p;
for(;*p && *p!='>'; p++)
if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
break; /* kr95-10-9: needs to stop here */
} else if (*p == '(') { /* Comment */
for(;*p && *p!=')'; p++)
if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
p++;
} else { /* Spool field */
start = p;
while(*p && !isspace((int) *p) && *p!=',' && *p!=';' && *p!='=')
p++;
break; /* Got it */
}
}
if (*p) *p++ = '\0';
*pstr = p;
return start;
}
uerr_t ftp_parse(ftpparse *fp,char *buf,int len)
{
char *cp;
char *token;
char *ptr;
char *date;
int i;
fp->filename = 0;
fp->namelen = 0;
// fp->flagtrycwd = 0;
// fp->flagtryretr = 0;
//fp->sizetype = FTPPARSE_SIZE_UNKNOWN;
fp->filesize = 0;
// fp->mtimetype = FTPPARSE_MTIME_UNKNOWN;
fp->mtime = 0;
// fp->idtype = FTPPARSE_ID_UNKNOWN;
fp->id = 0;
// fp->idlen = 0;
proz_debug("FTP LIST to be parsed is %s", cp=strdup(buf));
free(cp);
if (len < 2) /* an empty name in EPLF, with no info, could be 2 chars */
return FTPPARSENOTEXIST;
switch(*buf) {
case 'b':
case 'c':
case 'd':
case 'l':
case 'p':
case 's':
case '-':
/* UNIX-style listing, without inum and without blocks */
/* "-rw-r--r-- 1 root other 531 Jan 29 03:26 README" */
/* "dr-xr-xr-x 2 root other 512 Apr 8 1994 etc" */
/* "dr-xr-xr-x 2 root 512 Apr 8 1994 etc" */
/* "lrwxrwxrwx 1 root other 7 Jan 25 00:17 bin -> usr/bin" */
/* Also produced by Microsoft's FTP servers for Windows: */
/* "---------- 1 owner group 1803128 Jul 10 10:18 ls-lR.Z" */
/* "d--------- 1 owner group 0 May 9 19:45 Softlib" */
/* Also WFTPD for MSDOS: */
/* "-rwxrwxrwx 1 noone nogroup 322 Aug 19 1996 message.ftp" */
/* Also NetWare: */
/* "d [R----F--] supervisor 512 Jan 16 18:53 login" */
/* "- [R----F--] rhesus 214059 Oct 20 15:27 cx.exe" */
/* Also NetPresenz for the Mac: */
/* "-------r-- 326 1391972 1392298 Nov 22 1995 MegaPhone.sit" */
/* "drwxrwxr-x folder 2 May 10 1996 network"
*/
if (*buf == 'd') fp->filetype = DIRECTORY;
if (*buf == '-') fp->filetype = DIRECTORY;
if (*buf == 'l') fp->filetype = SYMBOLIC_LINK;
ptr=cp=strdup(buf);
for (i=0;i<4;i++)
{
//add checking
token= get_nextfield(&cp);
if(token == NULL) //failed to parse
return FTPPARSEFAIL;
}
/*
** This field can either be group or size. We find out by looking at the
** next field. If this is a non-digit then this field is the size.
*/
while (*cp && isspace((int) *cp)) cp++;
if (isdigit((int) *cp)) {
token = get_nextfield(&cp);
while (*cp && isspace((int) *cp)) cp++;
}
//if it is a filename
fp->filesize=strtol(token,NULL,10);
proz_debug("FTP file size is %ld", fp->filesize);
while (*cp && isspace((int) *cp)) cp++;
assert(cp+12<ptr+len);
date = cp;
cp += 12;
*cp++ = '\0';
fp->date_str = strdup(date);
proz_debug("LIST date is %s", fp->date_str);
return FTPPARSEOK;
default:
return FTPPARSEFAIL;
}
}
time_t parse_time(const char * str)
{
char * p;
struct tm tm;
time_t t;
if (!str) return 0;
if ((p = strchr(str, ',')))
{
}
return 0;
}

View File

@@ -0,0 +1,53 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* FTP LIST command parsing code. */
/* $Id: ftpparse.h,v 1.15 2005/08/06 17:07:35 kalum Exp $ */
#ifndef FTPPARSE_H
#define FTPPARSE_H
#include "common.h"
#include "prozilla.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ftpparse {
char *filename;
int namelen;
off_t filesize; /* number of octets */
// int mtimetype;
time_t mtime; /* modification time */
file_type_t filetype;
char *id; /* not necessarily 0-terminated */
char *date_str;
}ftpparse ;
uerr_t ftp_parse(ftpparse *fp,char *buf,int len);
#ifdef __cplusplus
}
#endif
#endif /* FTPPARSE_H */

1112
libprozilla/src/ftpsearch.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
#ifndef FTPSEARCH_H
#define FTPSEARCH_H
int ftpsearch_get_server_position(ftps_request_t * request, char *server);
int ftpsearch_get_path_position(ftps_request_t * request, char *server,
char *path);
#endif

530
libprozilla/src/http-retr.c Normal file
View File

@@ -0,0 +1,530 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* $Id: http-retr.c,v 1.20 2005/03/31 20:10:57 sean Exp $ */
#include "common.h"
#include "prozilla.h"
#include "connect.h"
#include "misc.h"
#include "url.h"
#include "netrc.h"
#include "debug.h"
#include "http.h"
#include "http-retr.h"
/* Will download a portion of/or the full file from the connection->url.
*/
uerr_t proz_http_get_file(connection_t * connection)
{
uerr_t err;
int remote_port_len;
char *user, *passwd, *www_auth = NULL, *proxy_auth = NULL, *range =
NULL, *location = NULL, *referer = NULL, *pragma_no_cache = NULL;
char *request, *remote_port;
netrc_entry *netrc_ent;
char buffer[HTTP_BUFFER_SIZE];
/*The http stats that were returned after the call with GET */
http_stat_t hs_after_get;
/* we want it to terminate immediately */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
assert(connection->localfile != NULL);
assert(connection->file_mode != NULL);
/*clear the socks */
connection->data_sock = 0;
memset(&hs_after_get, 0, sizeof(hs_after_get));
/* if there is nothing to download then return */
if (connection->status == COMPLETED)
{
pthread_mutex_lock(&connection->access_mutex);
gettimeofday(&connection->time_begin, NULL);
pthread_mutex_unlock(&connection->access_mutex);
return HOK;
}
connection_change_status(connection, CONNECTING);
if (http_use_proxy(connection))
{
connection_show_message(connection, _("Connecting to %s"),
connection->http_proxy->proxy_url.host);
err = connect_to_server(&connection->data_sock,
connection->http_proxy->proxy_url.host,
connection->http_proxy->proxy_url.port,
&connection->xfer_timeout);
if (err != NOCONERROR)
{
proz_debug(_("Error connecting to %s"),
connection->http_proxy->proxy_url.host);
connection_change_status(connection, REMOTEFATAL);
return err;
}
} else
{
connection_show_message(connection, _("Connecting to %s"),
connection->u.host);
err = connect_to_server(&connection->data_sock, connection->u.host,
connection->u.port, &connection->xfer_timeout);
if (err != NOCONERROR)
{
proz_debug(_("Error connecting to %s"), connection->u.host);
connection_change_status(connection, REMOTEFATAL);
return err;
}
}
user = connection->u.user;
passwd = connection->u.passwd;
/* Use .netrc if asked to do so. */
if (connection->use_netrc == TRUE)
{
netrc_ent = search_netrc(libprozrtinfo.netrc_list, connection->u.host);
if (netrc_ent != NULL)
{
user = netrc_ent->account;
passwd = netrc_ent->password;
}
}
user = user ? user : "";
passwd = passwd ? passwd : "";
if (strlen(user) || strlen(passwd))
{
/* Construct the necessary header. */
www_auth = get_basic_auth_str(user, passwd, "Authorization");
proz_debug(_("Authenticating as user %s password %s"), user, passwd);
proz_debug(_("Authentification string=%s"), www_auth);
} else
www_auth = 0;
if (http_use_proxy(connection))
{
if (strlen(connection->http_proxy->username)
|| strlen(connection->http_proxy->passwd))
proxy_auth =
get_basic_auth_str(connection->http_proxy->username,
connection->http_proxy->passwd,
"Proxy-Authorization");
}
if (connection->u.port == 80)
{
remote_port = NULL;
remote_port_len = 0;
} else
{
remote_port = (char *) alloca(64);
remote_port_len = sprintf(remote_port, ":%d", connection->u.port);
}
if (connection->hs.accept_ranges == 1)
{
range = (char *) alloca(18 + 64);
sprintf(range, "Range: bytes=%lld-\r\n", connection->remote_startpos);
proz_debug("Range = %lld Range = %s",connection->remote_startpos, range);
}
if (connection->u.referer)
{
referer = (char *) alloca(13 + strlen(connection->u.referer));
sprintf(referer, "Referer: %s\r\n", connection->u.referer);
}
/* If we go through a proxy the request for the URL is different */
if (http_use_proxy(connection))
{
location = (char *) alloca(strlen(connection->u.url) + 1);
strcpy(location, connection->u.url);
} else
{
location = (char *) alloca(strlen(connection->u.path) + 1);
strcpy(location, connection->u.path);
}
/*Use no-cache directive for proxy servers? */
if (http_use_proxy(connection)
&& (connection->http_no_cache || connection->attempts > 0))
{
pragma_no_cache = (char *) alloca(21);
sprintf(pragma_no_cache, "Pragma: no-cache\r\n");
}
request = (char *) alloca(strlen(location)
+ strlen(connection->user_agent)
+ strlen(connection->u.host) + remote_port_len
+ (range ? strlen(range) : 0)
+ (referer ? strlen(referer) : 0)
+ (www_auth ? strlen(www_auth) : 0)
+ (proxy_auth ? strlen(proxy_auth) : 0)
+ 64
+
(pragma_no_cache ? strlen(pragma_no_cache) :
0));
/* TODO Add referrer tag. */
sprintf(request,
"GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s%s\r\nAccept: */*\r\n%s%s%s%s%s\r\n",
location, connection->user_agent, connection->u.host,
remote_port ? remote_port : "", range ? range : "",
referer ? referer : "",
www_auth ? www_auth : "", proxy_auth ? proxy_auth : "",
pragma_no_cache ? pragma_no_cache : "");
proz_debug("2 HTTP request = %s", request);
connection_show_message(connection, _("Sending HTTP request"));
err = http_fetch_headers(connection, &hs_after_get, request);
/* What hapenned ? */
if (err != HOK)
{
proz_debug("2 http_fetch_headers err != HOK %d", err);
/*Check if we authenticated using any user or password and if we
were kicked out, if so return HAUTHFAIL */
if (err == HAUTHREQ && (strlen(user) || strlen(passwd)))
err = HAUTHFAIL;
/*
* a error occured druing the process
*/
close_sock(&connection->data_sock);
connection_change_status(connection, REMOTEFATAL);
return err;
}
/*Check for the server lying about it being able to handle ranges */
if (hs_after_get.contlen != -1)
{
if (connection->resume_support == TRUE)
{
if (hs_after_get.contlen !=
connection->main_file_size - connection->remote_startpos)
{
proz_debug("Error contlen does not match the requested range!");
close_sock(&connection->data_sock);
connection_change_status(connection, REMOTEFATAL);
return CANTRESUME;
}
}
}
/* which routine to call */
if (connection->main_file_size == -1)
err =
connection_retr_fsize_not_known(connection, buffer,
sizeof(buffer));
else
err = connection_retr_fsize_known(connection, buffer, sizeof(buffer));
close_sock(&connection->data_sock);
if (err == FILEGETOK)
return HOK;
else
{
proz_debug("err != FILEGETOK %d", err);
return err;
}
}
/* A genuine loop ;) It willed be called by the main thread, and
this will handle all possible errors itself, retrying until the number
of maximum tries for the connection is realised
*/
uerr_t http_loop(connection_t * connection)
{
boolean retrying_from_loop = FALSE;
assert(connection->max_attempts >= 0);
assert(connection->attempts >= 0);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
do
{
if (connection->attempts > 0)
{
if (retrying_from_loop == TRUE)
{
connection_show_message(connection,
_("Retrying...Attempt %d in %d seconds"),
connection->attempts,
connection->retry_delay.tv_sec);
delay_ms(connection->retry_delay.tv_sec * 1000);
}
if (connection->resume_support == TRUE)
{
if (connection_load_resume_info(connection) == -1)
{
connection_show_message(connection,
_
("Error while attemting to process download file "));
}
} else
{
/*If we cant resume then reset the connections bytesreceived to 0 */
connection->remote_bytes_received = 0;
}
}
/*Push the handler which will cleanup any sockets that are left open */
pthread_cleanup_push(cleanup_socks, (void *) connection);
connection->err = proz_http_get_file(connection);
/*pop the handler */
pthread_cleanup_pop(0);
connection->attempts++;
/*Should the error be handled at this level ? */
if (!http_loop_handle_error(connection->err))
{
connection_show_message(connection, _("Will be handled in main "));
return connection->err; /*If not return and the main thread will handle it */
}
switch (connection->err)
{
case HOK:
connection_show_message(connection, _("Successfully got download"));
return connection->err;
break;
/*TODO : What should we do if the file is not found, well pass it up to the main routine */
default:
connection_show_message(connection, proz_strerror(connection->err));
break;
}
retrying_from_loop = TRUE;
}
while ((connection->attempts < connection->max_attempts)
|| connection->max_attempts == 0);
connection_show_message(connection,
_
("I have tried %d attempt(s) and have failed, aborting"),
connection->attempts);
return connection->err;
}
/*Return true if it is a error which can be handled within the htp_loop,
or false if it should be passed upwards so that the main download thread can
restart it when necessary after processing other threads status too */
boolean http_loop_handle_error(uerr_t err)
{
proz_debug("Error encountered in http_loop is %d", err);
if (err == HTTPNSFOD || err == FWRITEERR || err == FOPENERR
|| err == CANTRESUME)
return FALSE;
else
return TRUE;
}
/*
I am writing a seperate function to handle FTP proxying through HTTP, I
MHO whoever thought of using HTTP to proxy FTP is a shithead,
its such a PITA ;)
*/
uerr_t ftp_get_file_from_http_proxy(connection_t * connection)
{
uerr_t err;
int remote_port_len;
char *user, *passwd, *www_auth = NULL, *proxy_auth = NULL, *range =
NULL, *pragma_no_cache = NULL;
char *request, *remote_port;
netrc_entry *netrc_ent;
char buffer[HTTP_BUFFER_SIZE];
/*The http stats that were returned after the call with GET */
http_stat_t hs_after_get;
/* we want it to terminate immediately */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
memset(&connection->hs, 0, sizeof(connection->hs));
memset(&hs_after_get, 0, sizeof(hs_after_get));
/* if there is nothing to download then return */
if (connection->status == COMPLETED)
{
pthread_mutex_lock(&connection->access_mutex);
gettimeofday(&connection->time_begin, NULL);
pthread_mutex_unlock(&connection->access_mutex);
return FTPOK;
}
err = connect_to_server(&connection->data_sock,
connection->ftp_proxy->proxy_url.host,
connection->ftp_proxy->proxy_url.port,
&connection->xfer_timeout);
if (err != NOCONERROR)
{
connection_show_message(connection, _("Error connecting to %s"),
connection->ftp_proxy->proxy_url.host);
return err;
}
user = connection->u.user;
passwd = connection->u.passwd;
/* Use .netrc if asked to do so. */
if (connection->use_netrc == TRUE)
{
netrc_ent = search_netrc(libprozrtinfo.netrc_list, connection->u.host);
if (netrc_ent != NULL)
{
user = netrc_ent->account;
passwd = netrc_ent->password;
}
}
user = user ? user : "";
passwd = passwd ? passwd : "";
if (strlen(user) || strlen(passwd))
{
/* Construct the necessary header. */
www_auth = get_basic_auth_str(user, passwd, "Authorization");
proz_debug(_("Authenticating as user %s password %s"), user, passwd);
proz_debug(_("Authentification string=%s"), www_auth);
} else
www_auth = 0;
if (strlen(connection->ftp_proxy->username)
|| strlen(connection->ftp_proxy->passwd))
proxy_auth =
get_basic_auth_str(connection->ftp_proxy->username,
connection->ftp_proxy->passwd,
"Proxy-Authorization");
remote_port = (char *) alloca(64);
remote_port_len = sprintf(remote_port, ":%d", connection->u.port);
if (connection->hs.accept_ranges == 1)
{
range = (char *) alloca(18 + 64);
sprintf(range, "Range: bytes=%lld-\r\n", connection->remote_startpos);
}
/*Use no-cache directive for proxy servers? */
if (http_use_proxy(connection)
&& (connection->http_no_cache || connection->attempts > 0))
{
pragma_no_cache = (char *) alloca(21);
sprintf(pragma_no_cache, "Pragma: no-cache\r\n");
}
/*Referrer TAG should not be needed in FTP through HTTP proxy..right */
request = (char *) alloca(strlen(connection->u.url)
+ strlen(connection->user_agent)
+ strlen(connection->u.host) + remote_port_len
+ (range ? strlen(range) : 0)
+ (www_auth ? strlen(www_auth) : 0)
+ (proxy_auth ? strlen(proxy_auth) : 0)
+ 64
+
(pragma_no_cache ? strlen(pragma_no_cache) :
0));
/* TODO Add referrer tag. */
sprintf(request,
"GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s%s\r\nAccept: */*\r\n%s%s%s%s\r\n",
connection->u.url, connection->user_agent, connection->u.host,
remote_port ? remote_port : "", range ? range : "",
www_auth ? www_auth : "", proxy_auth ? proxy_auth : "",
pragma_no_cache ? pragma_no_cache : "");
proz_debug("HTTP request = %s", request);
connection_show_message(connection, _("Sending HTTP request"));
err = http_fetch_headers(connection, &hs_after_get, request);
if (err == HAUTHREQ)
{
connection_change_status(connection, LOGINFAIL);
return FTPLOGREFUSED;
} else if (err == HTTPNSFOD)
{
connection_change_status(connection, REMOTEFATAL);
return FTPNSFOD;
} else if (err != HOK)
{
connection_change_status(connection, REMOTEFATAL);
return FTPERR;
}
/*Check for the server lying about it being able to handle ranges */
if (hs_after_get.contlen != -1)
{
if (connection->resume_support == TRUE)
{
if (hs_after_get.contlen !=
connection->main_file_size - connection->remote_startpos)
{
proz_debug("Error contlen does not match the requested range!");
connection_change_status(connection, REMOTEFATAL);
return CANTRESUME;
}
}
}
/* which routine to call */
if (connection->main_file_size == -1)
err =
connection_retr_fsize_not_known(connection, buffer,
sizeof(buffer));
else
err = connection_retr_fsize_known(connection, buffer, sizeof(buffer));
close_sock(&connection->data_sock);
if (err == FILEGETOK)
return FTPOK;
else
return err;
}

View File

@@ -0,0 +1,39 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* $Id: http-retr.h,v 1.5 2001/06/25 12:30:56 kalum Exp $ */
#ifndef HTTP_RETR_H
#define HTTP_RETR_H
#include "common.h"
#include "connection.h"
#ifdef __cplusplus
extern "C" {
#endif
uerr_t proz_http_get_file(connection_t * connection);
uerr_t http_loop(connection_t * connection);
boolean http_loop_handle_error(uerr_t err);
#ifdef __cplusplus
}
#endif
#endif /* FTP_RETR_H */

901
libprozilla/src/http.c Normal file
View File

@@ -0,0 +1,901 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* HTTP support. */
/* $Id: http.c,v 1.22 2005/03/31 20:10:57 sean Exp $ */
#include "common.h"
#include "prozilla.h"
#include "misc.h"
#include "connect.h"
#include "debug.h"
#include "http.h"
/* Some status code validation macros: */
#define H_20X(x) (((x) >= 200) && ((x) < 300))
#define H_PARTIAL(x) ((x) == HTTP_PARTIAL_CONTENTS)
#define H_REDIRECTED(x) (((x) == HTTP_MOVED_PERMANENTLY) || ((x) == HTTP_MOVED_TEMPORARILY))
/* HTTP/1.0 status codes from RFC1945, given for reference. */
/* Successful 2xx. */
#define HTTP_OK 200
#define HTTP_CREATED 201
#define HTTP_ACCEPTED 202
#define HTTP_NO_CONTENT 204
#define HTTP_PARTIAL_CONTENTS 206
/* Redirection 3xx. */
#define HTTP_MULTIPLE_CHOICES 300
#define HTTP_MOVED_PERMANENTLY 301
#define HTTP_MOVED_TEMPORARILY 302
#define HTTP_NOT_MODIFIED 304
/* Client error 4xx. */
#define HTTP_BAD_REQUEST 400
#define HTTP_UNAUTHORIZED 401
#define HTTP_FORBIDDEN 403
#define HTTP_NOT_FOUND 404
/* Server errors 5xx. */
#define HTTP_INTERNAL 500
#define HTTP_NOT_IMPLEMENTED 501
#define HTTP_BAD_GATEWAY 502
#define HTTP_UNAVAILABLE 503
#define HTTP_GATEWAY_TIMEOUT 504
#define DYNAMIC_LINE_BUFFER 40
/******************************************************************************
...
******************************************************************************/
int buf_readchar(int fd, char *ret, struct timeval *timeout)
{
int res;
res = krecv(fd, ret, 1, 0, timeout);
if (res <= 0)
return res;
return 1;
}
/******************************************************************************
This is similar to buf_readchar(), only it doesn't move the buffer position.
******************************************************************************/
int buf_peek(int fd, char *ret, struct timeval *timeout)
{
int res;
res = krecv(fd, ret, 1, MSG_PEEK, timeout);
if (res <= 0)
return res;
return 1;
}
/******************************************************************************
Function to fetch a header from socket/file descriptor fd. The header may be
of arbitrary length, since the function allocates as much memory as necessary
for the header to fit. Most errors are handled.
The header may be terminated by LF or CRLF. If the character after LF is SP
or HT (horizontal tab), the header spans to another line (continuation
header), as per RFC2068.
The trailing CRLF or LF are stripped from the header, and it is
zero-terminated.
******************************************************************************/
uerr_t fetch_next_header(int fd, char **hdr, struct timeval * timeout)
{
int i, bufsize, res;
char next;
bufsize = DYNAMIC_LINE_BUFFER;
*hdr = kmalloc(bufsize);
for (i = 0; 1; i++)
{
if (i > bufsize - 1)
*hdr = krealloc(*hdr, (bufsize <<= 1));
res = buf_readchar(fd, *hdr + i, timeout);
if (res == 1)
{
if ((*hdr)[i] == '\n')
{
if (!(i == 0 || (i == 1 && (*hdr)[0] == '\r')))
{
/* If the header is non-empty, we need to check if it continues on
to the other line. We do that by getting the next character
without actually downloading it (i.e. peeking it). */
res = buf_peek(fd, &next, timeout);
if (res == 0)
return HEOF;
else if (res == -1)
return HERR;
/* If the next character is SP or HT, just continue. */
if (next == '\t' || next == ' ')
continue;
}
/* The header ends. */
(*hdr)[i] = '\0';
/* Get rid of '\r'. */
if (i > 0 && (*hdr)[i - 1] == '\r')
(*hdr)[i - 1] = '\0';
break;
}
} else if (res == 0)
return HEOF;
else
return HERR;
}
return HOK;
}
/******************************************************************************
...
******************************************************************************/
int hparsestatline(const char *hdr, const char **rp)
{
int mjr, mnr; /* HTTP major and minor version. */
int statcode; /* HTTP status code. */
const char *p;
*rp = NULL;
/* The standard format of HTTP-Version is: HTTP/x.y, where x is major
version, and y is minor version. */
if (strncmp(hdr, "HTTP/", 5) != 0)
return -1;
hdr += 5;
p = hdr;
for (mjr = 0; isdigit(*hdr); hdr++)
mjr = 10 * mjr + (*hdr - '0');
if (*hdr != '.' || p == hdr)
return -1;
++hdr;
p = hdr;
for (mnr = 0; isdigit(*hdr); hdr++)
mnr = 10 * mnr + (*hdr - '0');
if (*hdr != ' ' || p == hdr)
return -1;
/* Wget will accept only 1.0 and higher HTTP-versions. The value of minor
version can be safely ignored. */
if (mjr < 1)
return -1;
/* Skip the space. */
++hdr;
if (!(isdigit(*hdr) && isdigit(hdr[1]) && isdigit(hdr[2])))
return -1;
statcode = 100 * (*hdr - '0') + 10 * (hdr[1] - '0') + (hdr[2] - '0');
/* RFC2068 requires a SPC here, even if there is no reason-phrase. As some
servers/CGI are (incorrectly) setup to drop the SPC, we'll be liberal
and allow the status line to end here. */
if (hdr[3] != ' ')
{
if (!hdr[3])
*rp = hdr + 3;
else
return -1;
} else
*rp = hdr + 4;
return statcode;
}
/******************************************************************************
Skip LWS (linear white space), if present. Returns number of characters to
skip.
******************************************************************************/
int hskip_lws(const char *hdr)
{
int i;
for (i = 0;
*hdr == ' ' || *hdr == '\t' || *hdr == '\r' || *hdr == '\n'; ++hdr)
++i;
return i;
}
/******************************************************************************
Return the content length of the document body, if this is Content-length
header, -1 otherwise.
******************************************************************************/
off_t hgetlen(const char *hdr)
{
const int l = 15; /* strlen("content-length:"). */
off_t len;
if (strncasecmp(hdr, "content-length:", l))
return -1;
hdr += (l + hskip_lws(hdr + l));
if (!*hdr)
return -1;
if (!isdigit(*hdr))
return -1;
for (len = 0; isdigit(*hdr); hdr++)
len = 10 * len + (*hdr - '0');
proz_debug("contenlen %s contentlen %lld",*hdr,len);
return len;
}
/******************************************************************************
Return the content-range in bytes, as returned by the server, if this is
Content-range header, -1 otherwise.
******************************************************************************/
off_t hgetrange(const char *hdr)
{
const int l = 14; /* strlen("content-range:"). */
off_t len;
if (strncasecmp(hdr, "content-range:", l))
return -1;
hdr += (l + hskip_lws(hdr + l));
if (!*hdr)
return -1;
/* Nutscape proxy server sends content-length without "bytes" specifier,
which is a breach of HTTP/1.1 draft. But heck, I must support it... */
if (!strncasecmp(hdr, "bytes", 5))
{
hdr += 5;
hdr += hskip_lws(hdr);
if (!*hdr)
return -1;
}
if (!isdigit(*hdr))
return -1;
for (len = 0; isdigit(*hdr); hdr++)
len = 10 * len + (*hdr - '0');
proz_debug("range %s range %lld",*hdr,len);
return len;
}
/******************************************************************************
Returns a malloc-ed copy of the location of the document, if the string hdr
begins with LOCATION_H, or NULL.
******************************************************************************/
char *hgetlocation(const char *hdr)
{
const int l = 9; /* strlen("location:"). */
if (strncasecmp(hdr, "location:", l))
return NULL;
hdr += (l + hskip_lws(hdr + l));
return kstrdup(hdr);
}
/******************************************************************************
Returns a malloc-ed copy of the last-modified date of the document, if the
hdr begins with LASTMODIFIED_H.
******************************************************************************/
char *hgetmodified(const char *hdr)
{
const int l = 14; /* strlen("last-modified:"). */
if (strncasecmp(hdr, "last-modified:", l))
return NULL;
hdr += (l + hskip_lws(hdr + l));
return kstrdup(hdr);
}
/******************************************************************************
Returns 0 if the header is accept-ranges, and it contains the word "none",
-1 if there is no accept ranges, 1 is there is accept-ranges and it is not
none.
******************************************************************************/
int hgetaccept_ranges(const char *hdr)
{
const int l = 14; /* strlen("accept-ranges:"). */
if (strncasecmp(hdr, "accept-ranges:", l))
return -1;
hdr += (l + hskip_lws(hdr + l));
if (strstr(hdr, "none"))
return 0;
else
return 1;
}
/******************************************************************************
...
******************************************************************************/
uerr_t http_fetch_headers(connection_t * connection, http_stat_t * hs,
char *command)
{
uerr_t err;
int num_written, hcount, statcode, all_length;
off_t contlen, contrange;
char *hdr, *type, *all_headers;
const char *error;
hs->len = 0L;
hs->contlen = -1;
hs->accept_ranges = -1;
hs->res = -1;
hs->newloc = NULL;
hs->remote_time = NULL;
hs->error = NULL;
num_written = ksend(connection->data_sock, command, strlen(command), 0,
&connection->xfer_timeout);
if (num_written != strlen(command))
{
proz_debug(_("Failed writing HTTP request"));
return WRITEERR;
}
all_headers = NULL;
all_length = 0;
contlen = contrange = -1;
statcode = -1;
type = NULL;
/* Header-fetching loop. */
hcount = 0;
for (;;)
{
++hcount;
/* Get the header. */
err = fetch_next_header(connection->data_sock, &hdr,
&connection->xfer_timeout);
proz_debug(_("Header = %s"), hdr);
if (err == HEOF)
{
proz_debug(_("End of file while parsing headers"));
kfree(hdr);
if (type)
kfree(type);
if (all_headers)
kfree(all_headers);
return HEOF;
} else if (err == HERR)
{
proz_debug(_("Read error in headers"));
kfree(hdr);
if (type)
kfree(type);
if (all_headers)
kfree(all_headers);
return HERR;
}
/* Exit on empty header. */
if (!*hdr)
{
kfree(hdr);
break;
}
/* Check for errors documented in the first header. */
if (hcount == 1)
{
statcode = hparsestatline(hdr, &error);
hs->statcode = statcode;
/* Store the descriptive response. */
if (statcode == -1) /* Malformed request. */
hs->error = kstrdup(_("UNKNOWN"));
else if (!*error)
hs->error = kstrdup(_("(no description)"));
else
hs->error = kstrdup(error);
}
if (contlen == -1)
{
contlen = hgetlen(hdr);
hs->contlen = contlen;
}
/* If the server specified a new location then lets store it. */
if (!hs->newloc)
hs->newloc = hgetlocation(hdr);
if (!hs->remote_time)
hs->remote_time = hgetmodified(hdr);
if (hs->accept_ranges == -1)
hs->accept_ranges = hgetaccept_ranges(hdr);
if (!hs->newloc)
hs->newloc = hgetlocation(hdr);
kfree(hdr);
}
if (H_20X(statcode))
return HOK;
if (H_REDIRECTED(statcode) || statcode == HTTP_MULTIPLE_CHOICES)
{
/* RFC2068 says that in case of the 300 (multiple choices) response, the
server can output a preferred URL through `Location' header; otherwise,
the request should be treated like GET. So, if the location is set, it
will be a redirection; otherwise, just proceed normally. */
if (statcode == HTTP_MULTIPLE_CHOICES && !hs->newloc)
return HOK;
else
{
if (all_headers)
kfree(all_headers);
if (type)
kfree(type);
return NEWLOCATION;
}
}
if (statcode == HTTP_UNAUTHORIZED)
return HAUTHREQ;
if (statcode == HTTP_NOT_FOUND)
return HTTPNSFOD;
if (statcode == HTTP_INTERNAL)
return INTERNALSERVERR;
if (statcode == HTTP_NOT_IMPLEMENTED)
return UNKNOWNREQ;
if (statcode == HTTP_BAD_GATEWAY)
return BADGATEWAY;
if (statcode == HTTP_UNAVAILABLE)
return SERVICEUNAVAIL;
if (statcode == HTTP_GATEWAY_TIMEOUT)
return GATEWAYTIMEOUT;
return HERR;
}
/******************************************************************************
...
******************************************************************************/
char *get_basic_auth_str(char *user, char *passwd, char *auth_header)
{
char *p1, *p2, *ret;
int len = strlen(user) + strlen(passwd) + 1;
int b64len = 4 * ((len + 2) / 3);
p1 = kmalloc(len + 1);
sprintf(p1, "%s:%s", user, passwd);
p2 = kmalloc(b64len + 1);
/* Encode username:passwd to base64. */
base64_encode(p1, p2, len);
ret = kmalloc(strlen(auth_header) + b64len + 11);
sprintf(ret, "%s: Basic %s\r\n", auth_header, p2);
kfree(p1);
kfree(p2);
return ret;
}
/******************************************************************************
...
******************************************************************************/
boolean http_use_proxy(connection_t * connection)
{
return (connection->http_proxy && connection->http_proxy->use_proxy
&& connection->http_proxy->proxy_url.url) ? TRUE : FALSE;
}
/******************************************************************************
...
******************************************************************************/
uerr_t proz_http_get_url_info(connection_t * connection)
{
uerr_t err;
int remote_port_len;
char *user, *passwd, *www_auth = NULL, *proxy_auth = NULL,
*referer = NULL, *location = NULL, *pragma_no_cache = NULL;
char *request, *remote_port;
netrc_entry *netrc_ent;
memset(&connection->hs, 0, sizeof(connection->hs));
if (http_use_proxy(connection))
{
connection_show_message(connection, _("Connecting to %s"),
connection->http_proxy->proxy_url.host);
err = connect_to_server(&connection->data_sock,
connection->http_proxy->proxy_url.host,
connection->http_proxy->proxy_url.port,
&connection->xfer_timeout);
if (err != NOCONERROR)
{
connection_show_message(connection, _("Error connecting to %s"),
connection->http_proxy->proxy_url.host);
return err;
}
} else
{
connection_show_message(connection, _("Connecting to %s"),
connection->u.host);
err = connect_to_server(&connection->data_sock, connection->u.host,
connection->u.port, &connection->xfer_timeout);
if (err != NOCONERROR)
{
connection_show_message(connection, _("Error connecting to %s"),
connection->u.host);
return err;
}
}
user = connection->u.user;
passwd = connection->u.passwd;
/* Use .netrc if asked to do so. */
if (connection->use_netrc == TRUE)
{
netrc_ent = search_netrc(libprozrtinfo.netrc_list, connection->u.host);
if (netrc_ent != NULL)
{
user = netrc_ent->account;
passwd = netrc_ent->password;
}
}
user = user ? user : "";
passwd = passwd ? passwd : "";
if (strlen(user) || strlen(passwd))
{
/* Construct the necessary header. */
www_auth = get_basic_auth_str(user, passwd, "Authorization");
proz_debug(_("Authenticating as user %s password %s"), user, passwd);
proz_debug(_("Authentification string=%s"), www_auth);
} else
www_auth = 0;
if (http_use_proxy(connection))
{
if (strlen(connection->http_proxy->username)
|| strlen(connection->http_proxy->passwd))
proxy_auth =
get_basic_auth_str(connection->http_proxy->username,
connection->http_proxy->passwd,
"Proxy-Authorization");
}
if (connection->u.port == 80)
{
remote_port = NULL;
remote_port_len = 0;
} else
{
remote_port = (char *) alloca(64);
remote_port_len = sprintf(remote_port, ":%d", connection->u.port);
}
if (connection->u.referer)
{
referer = (char *) alloca(13 + strlen(connection->u.referer));
sprintf(referer, "Referer: %s\r\n", connection->u.referer);
}
/* If we go through a proxy the request for the URL is different */
if (http_use_proxy(connection))
{
location = (char *) alloca(strlen(connection->u.url) + 1);
strcpy(location, connection->u.url);
} else
{
location = (char *) alloca(strlen(connection->u.path) + 1);
strcpy(location, connection->u.path);
}
/*Use no-cache directive for proxy servers? */
if (http_use_proxy(connection)
&& (connection->http_no_cache || connection->attempts > 0))
{
pragma_no_cache = (char *) alloca(21);
sprintf(pragma_no_cache, "Pragma: no-cache\r\n");
}
request = (char *) alloca(strlen(location)
+ strlen(connection->user_agent)
+ strlen(connection->u.host) + remote_port_len
+ (referer ? strlen(referer) : 0)
+ (www_auth ? strlen(www_auth) : 0)
+ (proxy_auth ? strlen(proxy_auth) : 0) + 64
+
(pragma_no_cache ? strlen(pragma_no_cache) :
0));
sprintf(request,
"GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s%s\r\nAccept: */*\r\n%s%s%s%s\r\n",
location, connection->user_agent, connection->u.host,
remote_port ? remote_port : "",
referer ? referer : "",
www_auth ? www_auth : "", proxy_auth ? proxy_auth : "",
pragma_no_cache ? pragma_no_cache : "");
proz_debug("HTTP request = %s", request);
connection_show_message(connection, _("Sending HTTP request"));
err = http_fetch_headers(connection, &connection->hs, request);
close_sock(&connection->data_sock);
if (err == HOK)
{
connection->main_file_size = connection->hs.contlen;
if (connection->hs.accept_ranges == 1)
connection->resume_support = TRUE;
else if (connection->hs.accept_ranges == -1)
connection->resume_support = FALSE;
}
connection->file_type = REGULAR_FILE;
return err;
}
/*Loops for connection->attempts */
uerr_t http_get_url_info_loop(connection_t * connection)
{
pthread_mutex_lock(&connection->access_mutex);
connection->running = TRUE;
pthread_mutex_unlock(&connection->access_mutex);
assert(connection->attempts >= 0);
do
{
if (connection->attempts > 0 && connection->err != NEWLOCATION)
{
connection_show_message(connection,
_("Retrying...Attempt %d in %d seconds"),
connection->attempts,
connection->retry_delay.tv_sec);
delay_ms(connection->retry_delay.tv_sec * 1000);
}
/*Push the handler which will cleanup any sockets that are left open */
pthread_cleanup_push(cleanup_socks, (void *) connection);
connection->err = proz_http_get_url_info(connection);
/*pop the handler */
pthread_cleanup_pop(0);
connection->attempts++;
switch (connection->err)
{
case HOK:
connection_show_message(connection, _("Successfully got info"));
pthread_mutex_lock(&connection->access_mutex);
connection->running = FALSE;
pthread_mutex_unlock(&connection->access_mutex);
return connection->err;
break;
case NEWLOCATION:
return connection->err;
break;
case HTTPNSFOD:
connection_show_message(connection, _("File not found!"));
pthread_mutex_lock(&connection->access_mutex);
connection->running = FALSE;
pthread_mutex_unlock(&connection->access_mutex);
return connection->err;
break;
default:
connection_show_message(connection, proz_strerror(connection->err));
break;
}
}
while ((connection->attempts < connection->max_attempts)
|| connection->max_attempts == 0);
connection_show_message(connection,
_
("I have tried %d attempt(s) and have failed, aborting"),
connection->attempts);
pthread_mutex_lock(&connection->access_mutex);
connection->running = FALSE;
pthread_mutex_unlock(&connection->access_mutex);
return connection->err;
}
/*
I am writing a seperate function to handle FTP proxying through HTTP, I
MHO whoever thought of using HTTP to proxy FTP is a shithead,
its such a PITA ;)
*/
uerr_t ftp_get_url_info_from_http_proxy(connection_t * connection)
{
uerr_t err;
int remote_port_len;
char *user, *passwd, *www_auth = NULL, *proxy_auth =
NULL, *pragma_no_cache = NULL;
char *request, *remote_port;
netrc_entry *netrc_ent;
memset(&connection->hs, 0, sizeof(connection->hs));
err = connect_to_server(&connection->data_sock,
connection->ftp_proxy->proxy_url.host,
connection->ftp_proxy->proxy_url.port,
&connection->xfer_timeout);
if (err != NOCONERROR)
{
connection_show_message(connection, _("Error connecting to %s"),
connection->ftp_proxy->proxy_url.host);
return err;
}
user = connection->u.user;
passwd = connection->u.passwd;
/* Use .netrc if asked to do so. */
if (connection->use_netrc == TRUE)
{
netrc_ent = search_netrc(libprozrtinfo.netrc_list, connection->u.host);
if (netrc_ent != NULL)
{
user = netrc_ent->account;
passwd = netrc_ent->password;
}
}
user = user ? user : "";
passwd = passwd ? passwd : "";
if (strlen(user) || strlen(passwd))
{
/* Construct the necessary header. */
www_auth = get_basic_auth_str(user, passwd, "Authorization");
proz_debug(_("Authenticating as user %s password %s"), user, passwd);
proz_debug(_("Authentification string=%s"), www_auth);
} else
www_auth = 0;
if (strlen(connection->ftp_proxy->username)
|| strlen(connection->ftp_proxy->passwd))
proxy_auth =
get_basic_auth_str(connection->ftp_proxy->username,
connection->ftp_proxy->passwd,
"Proxy-Authorization");
remote_port = (char *) alloca(64);
remote_port_len = sprintf(remote_port, ":%d", connection->u.port);
if (http_use_proxy(connection)
&& (connection->http_no_cache || connection->attempts > 0))
{
pragma_no_cache = (char *) alloca(21);
sprintf(pragma_no_cache, "Pragma: no-cache\r\n");
}
/*Referrer TAG should not be needed in FTP through HTTP proxy..right */
request = (char *) alloca(strlen(connection->u.url)
+ strlen(connection->user_agent)
+ strlen(connection->u.host) + remote_port_len
+ (www_auth ? strlen(www_auth) : 0)
+ (proxy_auth ? strlen(proxy_auth) : 0)
+ 64
+
(pragma_no_cache ? strlen(pragma_no_cache) :
0));
sprintf(request,
"GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s%s\r\nAccept: */*\r\n%s%s%s\r\n",
connection->u.url, connection->user_agent, connection->u.host,
remote_port,
www_auth ? www_auth : "", proxy_auth ? proxy_auth : "",
pragma_no_cache ? pragma_no_cache : "");
proz_debug("HTTP request = %s", request);
err = http_fetch_headers(connection, &connection->hs, request);
close_sock(&connection->data_sock);
/*Convert the error code to the equivalent FTP one if possible */
if (err == HOK)
{
connection->main_file_size = connection->hs.contlen;
if (connection->hs.accept_ranges == 1)
connection->resume_support = TRUE;
else if (connection->hs.accept_ranges == -1)
connection->resume_support = FALSE;
return FTPOK;
}
if (err == HAUTHREQ)
return FTPLOGREFUSED;
else if (err == HTTPNSFOD)
return FTPNSFOD;
/* connection->file_type = REGULAR_FILE; */
return FTPERR;
}

60
libprozilla/src/http.h Normal file
View File

@@ -0,0 +1,60 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* HTTP support. */
/* $Id: http.h,v 1.12 2005/03/31 20:10:57 sean Exp $ */
#ifndef HTTP_H
#define HTTP_H
#include "common.h"
#include "url.h"
#include "connection.h"
#ifdef __cplusplus
extern "C" {
#endif
int buf_readchar(int fd, char *ret, struct timeval *timeout);
int buf_peek(int fd, char *ret, struct timeval *timeout);
uerr_t fetch_next_header(int fd, char **hdr, struct timeval *timeout);
int hparsestatline(const char *hdr, const char **rp);
int hskip_lws(const char *hdr);
off_t hgetlen(const char *hdr);
off_t hgetrange(const char *hdr);
char *hgetlocation(const char *hdr);
char *hgetmodified(const char *hdr);
int hgetaccept_ranges(const char *hdr);
uerr_t http_fetch_headers(connection_t * connection, http_stat_t * hs,
char *command);
char *get_basic_auth_str(char *user, char *passwd, char *auth_header);
boolean http_use_proxy(connection_t * connection);
uerr_t proz_http_get_url_info(connection_t * connection);
uerr_t http_get_url_info_loop(connection_t * connection);
#ifdef __cplusplus
}
#endif
#endif /* HTTP_H */

320
libprozilla/src/logfile.c Normal file
View File

@@ -0,0 +1,320 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
#include "common.h"
#include "prozilla.h"
#include "misc.h"
#include "logfile.h"
/*creates the log file and stores the info */
/*If download is not NULL will store info about the downloads connection allocations to it too.*/
int log_create_logfile(int num_connections, int file_size, char *url,
download_t * download)
{
char buffer[PATH_MAX];
FILE *fp = NULL;
int i;
logfile lf;
memset(&lf, 0, sizeof(lf));
/*
* Compute the name of the logfile
*/
snprintf(buffer, PATH_MAX, "%s/%s%s.log", download->log_dir,
download->u.file, DEFAULT_FILE_EXT);
if (!(fp = fopen(buffer, "wb")))
{
/*
* fixme add the error displaing to the main function
*/
download_show_message(download,
_("Error opening file %s for writing: %s"),
buffer, strerror(errno));
return -1;
}
lf.num_connections = num_connections;
lf.version = 1000;
lf.got_info = download == NULL ? 1 : 0;
lf.file_size = file_size;
lf.url_len = strlen(url);
/*Write the logfile header */
/* No of connections */
if (fwrite(&lf, 1, sizeof(lf), fp) != sizeof(lf))
{
download_show_message(download, _("Error writing to file %s: %s"),
buffer, strerror(errno));
fclose(fp);
return -1;
}
/* Now we write the url to it */
if (fwrite(url, 1, strlen(url), fp) != strlen(url))
{
download_show_message(download, _("Error writing to file %s: %s"),
buffer, strerror(errno));
fclose(fp);
return -1;
}
/*Now we write each of the connections start and end positions to the file if download is not null */
if (download != NULL)
{
for (i = 0; i < download->num_connections; i++)
{
pthread_mutex_lock(&download->pconnections[i]->access_mutex);
if (fwrite
(&download->pconnections[i]->local_startpos, 1,
sizeof(download->pconnections[i]->local_startpos),
fp) != sizeof(download->pconnections[i]->local_startpos))
{
pthread_mutex_unlock(&download->pconnections[i]->access_mutex);
download_show_message(download, _("Error writing to file %s: %s"),
buffer, strerror(errno));
fclose(fp);
return -1;
}
if (fwrite
(&download->pconnections[i]->orig_remote_startpos, 1,
sizeof(download->pconnections[i]->orig_remote_startpos),
fp) != sizeof(download->pconnections[i]->orig_remote_startpos))
{
pthread_mutex_unlock(&download->pconnections[i]->access_mutex);
download_show_message(download, _("Error writing to file %s: %s"),
buffer, strerror(errno));
fclose(fp);
return -1;
}
if (fwrite
(&download->pconnections[i]->remote_endpos, 1,
sizeof(download->pconnections[i]->remote_endpos),
fp) != sizeof(download->pconnections[i]->remote_endpos))
{
pthread_mutex_unlock(&download->pconnections[i]->access_mutex);
download_show_message(download, _("Error writing to file %s: %s"),
buffer, strerror(errno));
fclose(fp);
return -1;
}
if (fwrite
(&download->pconnections[i]->remote_bytes_received, 1,
sizeof(download->pconnections[i]->remote_bytes_received),
fp) != sizeof(download->pconnections[i]->remote_bytes_received))
{
pthread_mutex_unlock(&download->pconnections[i]->access_mutex);
download_show_message(download, _("Error writing to file %s: %s"),
buffer, strerror(errno));
fclose(fp);
return -1;
}
pthread_mutex_unlock(&download->pconnections[i]->access_mutex);
}
}
fclose(fp);
return 1;
}
/* returns 1 if the logfile exists, 0 if it doesn't and -1 on error*/
int proz_log_logfile_exists(download_t * download)
{
char buffer[PATH_MAX];
int ret;
struct stat st_buf;
/*
* Compute the name of the logfile
*/
snprintf(buffer, PATH_MAX, "%s/%s%s.log", download->log_dir,
download->u.file, DEFAULT_FILE_EXT);
ret = stat(buffer, &st_buf);
if (ret == -1)
{
if (errno == ENOENT)
return 0;
else
return -1;
} else
return 1;
}
/* delete the log file */
int proz_log_delete_logfile(download_t * download)
{
char buffer[PATH_MAX];
int ret;
snprintf(buffer, PATH_MAX, "%s/%s%s.log", download->log_dir,
download->u.file, DEFAULT_FILE_EXT);
ret = unlink(buffer);
if (ret == -1)
{
if (errno == ENOENT)
{
download_show_message(download, _("logfile doesn't exist"));
return 1;
} else
{
download_show_message(download, "Error: Unable to delete the logfile: %s", strerror(errno));
return -1;
}
}
return 1;
}
/* Read the logfile into the logfile structure */
int proz_log_read_logfile(logfile * lf, download_t * download,
boolean load_con_info)
{
char buffer[PATH_MAX];
FILE *fp = NULL;
int i;
/*
* Compute the name of the logfile
*/
snprintf(buffer, PATH_MAX, "%s/%s%s.log", download->log_dir,
download->u.file, DEFAULT_FILE_EXT);
if (!(fp = fopen(buffer, "rb")))
{
/*
* fixme add the error displaing to the main function
*/
download_show_message(download,
_("Error opening file %s for reading: %s"),
buffer, strerror(errno));
return -1;
}
if (fread(lf, 1, sizeof(logfile), fp) != sizeof(logfile))
{
fclose(fp);
return -1;
}
lf->url = kmalloc(lf->url_len + 1);
if (fread(lf->url, 1, lf->url_len, fp) != lf->url_len)
{
fclose(fp);
return -1;
}
lf->url[lf->url_len] = 0;
if (load_con_info == TRUE)
{
for (i = 0; i < lf->num_connections; i++)
{
proz_debug("value before= %d", download->pconnections[i]->local_startpos);
if (fread
(&download->pconnections[i]->local_startpos, 1,
sizeof(download->pconnections[i]->local_startpos),
fp) != sizeof(download->pconnections[i]->local_startpos))
{
download_show_message(download,
_("Error reading from file %s: %s"), buffer,
strerror(errno));
fclose(fp);
return -1;
}
proz_debug("value after= %d", download->pconnections[i]->local_startpos);
proz_debug("orig_remote_startpos before= %d", download->pconnections[i]->orig_remote_startpos);
if (fread
(&download->pconnections[i]->orig_remote_startpos, 1,
sizeof(download->pconnections[i]->orig_remote_startpos),
fp) != sizeof(download->pconnections[i]->orig_remote_startpos))
{
download_show_message(download,
_("Error reading from file %s: %s"), buffer,
strerror(errno));
fclose(fp);
return -1;
}
proz_debug("orig_remote_startpos after= %d", download->pconnections[i]->orig_remote_startpos);
proz_debug("remote_edndpos before= %d", download->pconnections[i]->remote_endpos);
if (fread
(&download->pconnections[i]->remote_endpos, 1,
sizeof(download->pconnections[i]->remote_endpos),
fp) != sizeof(download->pconnections[i]->remote_endpos))
{
download_show_message(download,
_("Error reading from file %s: %s"), buffer,
strerror(errno));
fclose(fp);
return -1;
}
proz_debug("remote_endpos after= %d", download->pconnections[i]->remote_endpos);
proz_debug("remote_bytes_received before= %d", download->pconnections[i]->remote_bytes_received);
if (fread
(&download->pconnections[i]->remote_bytes_received, 1,
sizeof(download->pconnections[i]->remote_bytes_received),
fp) != sizeof(download->pconnections[i]->remote_bytes_received))
{
download_show_message(download,
_("Error reading from file %s: %s"), buffer,
strerror(errno));
fclose(fp);
return -1;
}
proz_debug("remote_bytes_received after= %d", download->pconnections[i]->remote_bytes_received);
}
}
fclose(fp);
return 1;
}

41
libprozilla/src/logfile.h Normal file
View File

@@ -0,0 +1,41 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
#ifndef LOGFILE_H
#define LOGFILE_H
#include "common.h"
#include "prozilla.h"
#include "download.h"
#ifdef __cplusplus
extern "C" {
#endif
int log_create_logfile(int num_connections, int file_size, char *url,
download_t * download);
#ifdef __cplusplus
}
#endif
#endif

226
libprozilla/src/main.c Normal file
View File

@@ -0,0 +1,226 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* The main file. */
/* $Id: main.c,v 1.43 2005/03/31 20:10:57 sean Exp $ */
#include "common.h"
#include "prozilla.h"
#include "misc.h"
//#include "getopt.h"
#include "debug.h"
/* static struct option long_opts[] = {
// { name has_arg *flag val }
{"no-netrc", no_argument, NULL, 'n'},
{"use-port", no_argument, NULL, 129},
{"libdebug", no_argument, NULL, 130},
{NULL, 0, NULL, 0}
};*/
libprozinfo libprozrtinfo;
/******************************************************************************
Initialize the library.
******************************************************************************/
int proz_init(int argc, char **argv)
{
// int c;
/* Gettext stuff */
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
memset(&libprozrtinfo, 0, sizeof(libprozrtinfo));
libprozrtinfo.argc = argc;
libprozrtinfo.argv = argv;
libprozrtinfo.debug_mode = TRUE;
libprozrtinfo.ftp_use_pasv = TRUE;
libprozrtinfo.ftp_default_user = kstrdup(DEFAULT_FTP_USER);
libprozrtinfo.ftp_default_passwd = kstrdup(DEFAULT_FTP_PASSWD);
libprozrtinfo.use_netrc = TRUE;
libprozrtinfo.ftp_proxy = 0;
libprozrtinfo.http_proxy = 0;
/* 3 minutes should be enough for the default timeout */
libprozrtinfo.conn_timeout.tv_sec = 120;
libprozrtinfo.conn_timeout.tv_usec = 0;
/* 15 secs for the default retry_delay */
libprozrtinfo.conn_retry_delay.tv_sec = 15;
libprozrtinfo.conn_retry_delay.tv_usec = 0;
/*Default: try infinitely */
libprozrtinfo.max_attempts = 0;
/*No no-cache directive is given */
libprozrtinfo.http_no_cache = FALSE;
/*default is unlimited (0) bandwith */
libprozrtinfo.max_bps_per_dl = 0;
/* Parse the options and set the relevant ones for the library. */
/* while ((c = getopt_long(argc, argv, "", long_opts, NULL)) != EOF)
{
switch (c)
{
case 129:
libprozrtinfo.debug_mode = TRUE;
break;
default:
continue;
}
}
*/
/* TODO Get home directory and read .netrc. */
libprozrtinfo.home_dir = home_dir();
if (libprozrtinfo.home_dir != NULL)
{
char *netrc_file = kmalloc(strlen(libprozrtinfo.home_dir)
+ strlen(".netrc") + 2);
sprintf(netrc_file, "%s/%s", libprozrtinfo.home_dir, ".netrc");
libprozrtinfo.netrc_list = parse_netrc(netrc_file);
}
libprozrtinfo.dl_dir = kstrdup(".");
libprozrtinfo.output_dir = kstrdup(".");
libprozrtinfo.log_dir = kstrdup(".");
debug_init();
return 1;
}
/******************************************************************************
...
******************************************************************************/
void proz_shutdown(void)
{
kfree(libprozrtinfo.http_proxy);
kfree(libprozrtinfo.ftp_proxy);
kfree(libprozrtinfo.dl_dir);
kfree(libprozrtinfo.output_dir);
kfree(libprozrtinfo.log_dir);
}
/******************************************************************************
Abort with an error message.
******************************************************************************/
void proz_die(const char *format, ...)
{
va_list args;
char message[MAX_MSG_SIZE + 1];
va_start(args, format);
vsnprintf(message, MAX_MSG_SIZE, format, args);
va_end(args);
printf("%s\n", message);
proz_shutdown();
exit(EXIT_FAILURE);
}
/******************************************************************************
...
******************************************************************************/
void proz_set_http_proxy(proxy_info * proxy)
{
if (libprozrtinfo.http_proxy)
kfree(libprozrtinfo.http_proxy);
libprozrtinfo.http_proxy = kmalloc(sizeof(proxy_info));
memcpy(libprozrtinfo.http_proxy, proxy, sizeof(proxy_info));
}
/******************************************************************************
...
******************************************************************************/
void proz_set_ftp_proxy(proxy_info * proxy)
{
if (libprozrtinfo.ftp_proxy)
kfree(libprozrtinfo.ftp_proxy);
libprozrtinfo.ftp_proxy = kmalloc(sizeof(proxy_info));
memcpy(libprozrtinfo.ftp_proxy, proxy, sizeof(proxy_info));
}
void proz_use_http_proxy(boolean use)
{
if (libprozrtinfo.http_proxy)
libprozrtinfo.http_proxy->use_proxy = use;
}
void proz_use_ftp_proxy(boolean use)
{
if (libprozrtinfo.ftp_proxy)
libprozrtinfo.ftp_proxy->use_proxy = use;
}
void proz_set_connection_timeout(struct timeval *timeout)
{
libprozrtinfo.conn_timeout.tv_sec = timeout->tv_sec;
libprozrtinfo.conn_timeout.tv_usec = timeout->tv_usec;
}
void proz_set_connection_retry_delay(struct timeval *delay)
{
libprozrtinfo.conn_retry_delay.tv_sec = delay->tv_sec;
libprozrtinfo.conn_retry_delay.tv_usec = delay->tv_usec;
}
void proz_set_download_dir(char *dir)
{
assert(dir != NULL);
if (libprozrtinfo.dl_dir)
kfree(libprozrtinfo.dl_dir);
libprozrtinfo.dl_dir = kstrdup(dir);
}
void proz_set_logfile_dir(char *dir)
{
assert(dir != NULL);
if (libprozrtinfo.log_dir)
kfree(libprozrtinfo.log_dir);
libprozrtinfo.log_dir = kstrdup(dir);
}
void proz_set_output_dir(char *dir)
{
assert(dir != NULL);
if (libprozrtinfo.output_dir)
kfree(libprozrtinfo.output_dir);
libprozrtinfo.output_dir = kstrdup(dir);
}
char *proz_get_libprozilla_version()
{
return strdup(VERSION);
}

527
libprozilla/src/misc.c Normal file
View File

@@ -0,0 +1,527 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* Miscellaneous routines. */
/* $Id: misc.c,v 1.32 2005/01/11 01:49:11 sean Exp $ */
#include "common.h"
#include "prozilla.h"
#include "misc.h"
#include "debug.h"
void cleanup_httpsocks(connection_t * connection);
void cleanup_ftpsocks(connection_t * connection);
/******************************************************************************
Allocates size bytes of memory. If size is 0 it returns NULL. If there is
not enough memory the program quits with an error message.
******************************************************************************/
void *kmalloc(size_t size)
{
void *ret;
if (size == 0)
return NULL;
ret = malloc(size);
if (ret == NULL)
proz_die(_("Failed to malloc() %lu bytes."), size);
return ret;
}
/******************************************************************************
A wrapper for realloc() which aborts if not enough memory is present.
******************************************************************************/
void *krealloc(void *ptr, size_t new_size)
{
void *ret;
ret = realloc(ptr, new_size);
if (!ret)
proz_die(_("Failed to realloc() %lu bytes."), new_size);
return ret;
}
/******************************************************************************
A wrapper for free() which handles NULL pointers.
******************************************************************************/
void kfree(void *ptr)
{
if (ptr != NULL)
free(ptr);
}
/******************************************************************************
A wrapper for strdup() which aborts if not enough memory is present.
******************************************************************************/
char *kstrdup(const char *str)
{
char *ret = strdup(str);
if (!ret)
proz_die(_("Not enough memory to continue: strdup() failed."));
return ret;
}
/******************************************************************************
Checks whether the specified string is a number or digit.
******************************************************************************/
boolean is_number(const char *str)
{
unsigned int i = 0;
if (str[0] == '\0')
return FALSE;
while (str[i] != '\0')
{
if (!isdigit(str[i]))
return FALSE;
i++;
}
return TRUE;
}
/******************************************************************************
How many digits are in a long integer?
******************************************************************************/
int numdigit(long a)
{
int res;
for (res = 1; (a /= 10) != 0; res++)
;
return res;
}
/******************************************************************************
Copy the string formed by two pointers (one on the beginning, other on the
char after the last char) to a new, malloc()-ed location. 0-terminate it.
******************************************************************************/
char *strdupdelim(const char *beg, const char *end)
{
char *res;
res = kmalloc(end - beg + 1);
memcpy(res, beg, end - beg);
res[end - beg] = '\0';
return res;
}
/******************************************************************************
Print a long integer to the string buffer. The digits are first written in
reverse order (the least significant digit first), and are then reversed.
******************************************************************************/
void prnum(char *where, long num)
{
char *p;
int i = 0, l;
char c;
if (num < 0)
{
*where++ = '-';
num = -num;
}
p = where;
/* Print the digits to the string. */
do
{
*p++ = num % 10 + '0';
num /= 10;
}
while (num);
/* And reverse them. */
l = p - where - 1;
for (i = l / 2; i >= 0; i--)
{
c = where[i];
where[i] = where[l - i];
where[l - i] = c;
}
where[l + 1] = '\0';
}
/******************************************************************************
Extracts a numurical argument from an option, when it has been specified for
example as -l=3 or -l3. Returns 1 on success or 0 on error (non numerical
argument etc).
******************************************************************************/
int setargval(char *optstr, int *num)
{
if (*optstr == '=')
{
if (is_number(optstr + 1))
{
*num = atoi(optstr + 1);
return 1;
} else
return 0;
} else
{
if (is_number(optstr))
{
*num = atoi(optstr);
return 1;
} else
return 0;
}
}
/******************************************************************************
Encode the given string to base64 format and place it into store. store will
be 0-terminated, and must point to a writable buffer of at least
1+BASE64_LENGTH(length) bytes. Note: Routine stolen from wget (grendel).
******************************************************************************/
void base64_encode(const char *s, char *store, int length)
{
/* Conversion table. */
char tbl[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'
};
int i;
unsigned char *p = (unsigned char *) store;
/* Transform the 3x8 bits to 4x6 bits, as required by base64. */
for (i = 0; i < length; i += 3)
{
*p++ = tbl[s[0] >> 2];
*p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
*p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
*p++ = tbl[s[2] & 0x3f];
s += 3;
}
/* Pad the result if necessary... */
if (i == length + 1)
*(p - 1) = '=';
else if (i == length + 2)
*(p - 1) = *(p - 2) = '=';
/* ...and zero-terminate it. */
*p = '\0';
}
/******************************************************************************
Return the user's home directory (strdup-ed), or NULL if none is found.
******************************************************************************/
char *home_dir(void)
{
char *home = getenv("HOME");
if (home == NULL)
{
/* If $HOME is not defined, try getting it from the passwd file. */
struct passwd *pwd = getpwuid(getuid());
if (!pwd || !pwd->pw_dir)
return NULL;
home = pwd->pw_dir;
}
return home ? kstrdup(home) : NULL;
}
/******************************************************************************
Subtract the `struct timeval' values X and Y, storing the result in RESULT.
Return 1 if the difference is negative, otherwise 0.
******************************************************************************/
int proz_timeval_subtract(struct timeval *result, struct timeval *x,
struct timeval *y)
{
/* Perform the carry for the later subtraction by updating Y. */
if (x->tv_usec < y->tv_usec)
{
int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
y->tv_usec -= 1000000 * nsec;
y->tv_sec += nsec;
}
if (x->tv_usec - y->tv_usec > 1000000)
{
int nsec = (x->tv_usec - y->tv_usec) / 1000000;
y->tv_usec += 1000000 * nsec;
y->tv_sec -= nsec;
}
/* Compute the time remaining to wait. `tv_usec' is certainly positive. */
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_usec = x->tv_usec - y->tv_usec;
/* Return 1 if result is negative. */
return x->tv_sec < y->tv_sec;
}
/******************************************************************************
Wait for 'ms' milliseconds.
******************************************************************************/
void delay_ms(int ms)
{
struct timeval tv_delay;
memset(&tv_delay, 0, sizeof(tv_delay));
tv_delay.tv_sec = ms / 1000;
tv_delay.tv_usec = (ms * 1000) % 1000000;
if (select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &tv_delay) < 0)
proz_debug(_("Warning: Unable to delay"));
}
/*Closes a socket and zeroes the socket before returning */
int close_sock(int *sock)
{
int retval = close(*sock);
*sock = 0;
return retval;
}
/*Returns a string representation of a prozilla errror */
char *proz_strerror(uerr_t error)
{
switch (error)
{
case HOSTERR:
return _("Unable to lookup hostname");
case CONSOCKERR:
return _("Unable to create socket");
case CONERROR:
return _("Error occured while connecting");
case CONREFUSED:
return _("The connection attempt was refused");
case ACCEPTERR:
return _("Error while accepting the connection");
case BINDERR:
return _("Error while Binding socket");
case LISTENERR:
return _("Error while listening");
case SERVERCLOSECONERR:
return _("The connection was reset/closed by the peer");
case URLUNKNOWN:
return _("The URL Protocol was unknown");
case URLBADPORT:
return _("The port specified in the URL is not valid!");
case URLBADHOST:
return _("The Hostname specified in the URL is not valid!");
case URLBADPATTERN:
return _("The Pattern specified in the URL does not look valid!");
case HEOF:
return _("End of file reached in HTTP connection");
case HERR:
return _("Error occured in HTTP data transfer");
case HAUTHREQ:
return _("Authentification is required to access this resource");
case HAUTHFAIL:
return _("Failed to Authenticate with host!");
case HTTPNSFOD:
return _("The URL was not found on the host!");
case FTPLOGREFUSED:
return _("The host disallowed the login attempt");
case FTPPORTERR:
return _("The PORT request was rejected by the server");
case FTPNSFOD:
return _("The object file/dir was not found on the host!");
case FTPUNKNOWNTYPE:
return _("The TYPE specified in not known by the FTP server!");
case FTPUNKNOWNCMD:
return _("The command is not known by the FTP server!");
case FTPSIZEFAIL:
return _("The SIZE command failed");
case FTPERR:
return _("Error occured in FTP data transfer");
case FTPRESTFAIL:
return _("The REST command failed");
case FTPACCDENIED:
return _("The peer did not allow access");
case FTPPWDERR:
return _("The host rejected the password");
case FTPPWDFAIL:
return _("The host rejected the password");
case FTPINVPASV:
return _("The PASV (passive mode) was not supported the host");
case FTPNOPASV:
return _("The host does not support PASV (passive mode) transfers");
case FTPCONREFUSED:
return _("The connection attempt was refused");
case FTPCWDFAIL:
return _("Failed to (CWD)change to the directory");
case FTPSERVCLOSEDATLOGIN:
return
_
("The host said the requested service was unavailable and closed the control connection");
case CONPORTERR:
return _("getsockname failed!");
case GATEWAYTIMEOUT:
return
_
("The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request");
case SERVICEUNAVAIL:
return
_
("The server is currently unable to handle the request due to a temporary overloading or maintenance of the server.");
case BADGATEWAY:
return
_
("The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request");
case INTERNALSERVERR:
return
_
("The server encountered an unexpected condition which prevented it from fulfilling the request.");
case UNKNOWNREQ:
return
_
("The server does not support the functionality required to fulfill the request.");
case FOPENERR:
return _("Error while opening file");
case FWRITEERR:
return _("Error while writing to file");
case DLABORTED:
return _("The Download was aborted");
case DLLOCALFATAL:
return _("The Download encountered a local fatal error");
case CANTRESUME:
return _("Error: Resuming this connection is not possible");
case READERR:
return _("Error while reading data from socket");
case WRITEERR:
return _("Error while writing data to socket");
case PROXERR:
return _("Error while Proxying");
case FILEISDIR:
return _("The location is a directory");
default:
return _("Unknown/Unsupported error code");
}
}
/* Cleanup handler which will be popped and which will be called when the thread is cancelled, it make sure that there will be no sockets left open if the thread is cancelled prematurely
*/
#include "ftp.h"
void cleanup_socks(void *cdata)
{
connection_t *connection = (connection_t *) cdata;
switch (connection->u.proto)
{
case URLHTTP:
cleanup_httpsocks(connection);
break;
case URLFTP:
if (ftp_use_proxy(connection)
&& connection->ftp_proxy->type == HTTPPROXY)
{
/* We have to cleanup the http socks instead
if we are going through a http proxy */
cleanup_httpsocks(connection);
} else
cleanup_ftpsocks(connection);
break;
default:
proz_die(_("Error: unsupported protocol"));
}
}
void cleanup_ftpsocks(connection_t * connection)
{
int flags;
proz_debug("in clean ftp sock\n");
if (connection->data_sock > 0)
{
flags = fcntl(connection->data_sock, F_GETFD, 0);
if (flags == -1)
{
proz_debug("data sock invalid\n");
} else
close_sock(&connection->data_sock);
}
if (connection->ctrl_sock > 0)
{
flags = fcntl(connection->ctrl_sock, F_GETFD, 0);
if (flags == -1)
{
proz_debug("control sock invalid\n");
} else
close_sock(&connection->ctrl_sock);
}
}
void cleanup_httpsocks(connection_t * connection)
{
int flags;
proz_debug("in clean http sock\n");
if (connection->data_sock > 0)
{
flags = fcntl(connection->data_sock, F_GETFD, 0);
if (flags == -1)
{
proz_debug("sock invalid\n");
} else
close(connection->data_sock);
}
}

49
libprozilla/src/misc.h Normal file
View File

@@ -0,0 +1,49 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* Miscellaneous routines. */
/* $Id: misc.h,v 1.25 2001/09/02 23:29:16 kalum Exp $ */
#ifndef MISC_H
#define MISC_H
#include "common.h"
#include "prozilla.h"
void *kmalloc(size_t size);
void kfree(void *ptr);
void *krealloc(void *ptr, size_t new_size);
char *kstrdup(const char *str);
boolean is_number(const char *str);
int numdigit(long a);
char *strdupdelim(const char *beg, const char *end);
void prnum(char *where, long num);
int setargval(char *optstr, int *num);
void base64_encode(const char *s, char *store, int length);
char *home_dir(void);
void delay_ms(int ms);
int close_sock(int *sock);
void cleanup_socks(void *cdata);
#endif /* MISC_H */

293
libprozilla/src/netrc.c Normal file
View File

@@ -0,0 +1,293 @@
/* netrc.c -- parse the .netrc file to get hosts, accounts, and passwords
Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Slightly modified for libprozilla, by Grendel <kalum@delrom.ro>. */
/* $Id: netrc.c,v 1.17 2001/08/09 23:35:26 kalum Exp $ */
#include "common.h"
#include "netrc.h"
#include "misc.h"
#define POPBUFSIZE BUFSIZ
/******************************************************************************
Maybe add NEWENTRY to the account information list, LIST. NEWENTRY is
set to a ready-to-use netrc_entry, in any event.
******************************************************************************/
static void maybe_add_to_list(netrc_entry ** newentry, netrc_entry ** list)
{
netrc_entry *a, *l;
a = *newentry;
l = *list;
/* We need an account name in order to add the entry to the list. */
if (a && !a->account)
{
/* Free any allocated space. */
if (a->host)
kfree(a->host);
if (a->password)
kfree(a->password);
} else
{
if (a)
{
/* Add the current machine into our list. */
a->next = l;
l = a;
}
/* Allocate a new netrc_entry structure. */
a = kmalloc(sizeof(netrc_entry));
}
/* Zero the structure, so that it is ready to use. */
memset(a, 0, sizeof(*a));
/* Return the new pointers. */
*newentry = a;
*list = l;
return;
}
/******************************************************************************
Parse FILE as a .netrc file (as described in ftp(1)), and return a list of
entries. NULL is returned if the file could not be parsed.
******************************************************************************/
netrc_entry *parse_netrc(char *file)
{
FILE *fp;
char buf[POPBUFSIZE + 1], *p, *tok;
const char *premature_token;
netrc_entry *current, *retval;
int ln;
/* The latest token we've seen in the file. */
enum {
tok_nothing, tok_account, tok_login, tok_macdef, tok_machine,
tok_password
} last_token = tok_nothing;
current = retval = NULL;
fp = fopen(file, "r");
if (!fp)
{
/* Just return NULL if we can't open the file. */
return NULL;
}
/* Initialize the file data. */
ln = 0;
premature_token = NULL;
/* While there are lines in the file... */
while (fgets(buf, POPBUFSIZE, fp))
{
ln++;
/* Strip trailing CRLF. */
for (p = buf + strlen(buf) - 1; (p >= buf) && isspace((unsigned) *p);
p--)
*p = '\0';
/* Parse the line. */
p = buf;
/* If the line is empty... */
if (!*p)
{
if (last_token == tok_macdef)
last_token = tok_nothing; /* End of macro. */
else
continue; /* Otherwise ignore it. */
}
/* If we are defining macros, then skip parsing the line. */
while (*p && last_token != tok_macdef)
{
char quote_char = 0;
char *pp;
/* Skip any whitespace. */
while (*p && isspace((unsigned) *p))
p++;
/* Discard end-of-line comments. */
if (*p == '#')
break;
tok = pp = p;
/* Find the end of the token. */
while (*p && (quote_char || !isspace((unsigned) *p)))
{
if (quote_char)
{
if (quote_char == *p)
{
quote_char = 0;
p++;
} else
{
*pp = *p;
p++;
pp++;
}
} else
{
if (*p == '"' || *p == '\'')
quote_char = *p;
else
{
*pp = *p;
pp++;
}
p++;
}
}
/* Null-terminate the token, if it isn't already. */
if (*p)
*p++ = '\0';
*pp = 0;
switch (last_token)
{
case tok_login:
if (current)
current->account = kstrdup(tok);
else
premature_token = "login";
break;
case tok_machine:
/* Start a new machine entry. */
maybe_add_to_list(&current, &retval);
current->host = kstrdup(tok);
break;
case tok_password:
if (current)
current->password = kstrdup(tok);
else
premature_token = "password";
break;
/* We handle most of tok_macdef above. */
case tok_macdef:
if (!current)
premature_token = "macdef";
break;
/* We don't handle the account keyword at all. */
case tok_account:
if (!current)
premature_token = "account";
break;
/* We handle tok_nothing below this switch. */
case tok_nothing:
break;
}
if (premature_token)
{
fprintf(stderr,
_("%s:%d: warning: found \"%s\" before any host names\n"),
file, ln, premature_token);
premature_token = NULL;
}
if (last_token != tok_nothing)
/* We got a value, so reset the token state. */
last_token = tok_nothing;
else
{
/* Fetch the next token. */
if (!strcmp(tok, "default"))
maybe_add_to_list(&current, &retval);
else if (!strcmp(tok, "login"))
last_token = tok_login;
else if (!strcmp(tok, "user"))
last_token = tok_login;
else if (!strcmp(tok, "macdef"))
last_token = tok_macdef;
else if (!strcmp(tok, "machine"))
last_token = tok_machine;
else if (!strcmp(tok, "password"))
last_token = tok_password;
else if (!strcmp(tok, "passwd"))
last_token = tok_password;
else if (!strcmp(tok, "account"))
last_token = tok_account;
else
fprintf(stderr, _("%s:%d: warning: unknown token \"%s\"\n"),
file, ln, tok);
}
}
}
fclose(fp);
/* Finalize the last machine entry we found. */
maybe_add_to_list(&current, &retval);
kfree(current);
/* Reverse the order of the list so that it appears in file order. */
current = retval;
retval = NULL;
while (current)
{
netrc_entry *saved_reference;
/* Change the direction of the pointers. */
saved_reference = current->next;
current->next = retval;
/* Advance to the next node. */
retval = current;
current = saved_reference;
}
return retval;
}
/******************************************************************************
Return the netrc entry from LIST corresponding to HOST. NULL is returned if
no such entry exists.
******************************************************************************/
netrc_entry *search_netrc(netrc_entry * list, const char *host)
{
/* Look for the HOST in LIST. */
while (list)
{
if (!list->host)
break; /* We hit the default entry. */
else if (!strcmp(list->host, host))
break; /* We found a matching entry. */
list = list->next;
}
/* Return the matching entry, or NULL. */
return list;
}

66
libprozilla/src/netrc.h Normal file
View File

@@ -0,0 +1,66 @@
/* netrc.h -- declarations for netrc.c
Copyright (C) 1996, Free Software Foundation, Inc.
Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* $Id: netrc.h,v 1.11 2001/05/30 15:01:40 kalum Exp $ */
#ifndef NETRC_H
#define NETRC_H
#include "common.h"
#undef __BEGIN_DECLS
#undef __END_DECLS
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS /* Empty. */
# define __END_DECLS /* Empty. */
#endif
#undef __P
#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(WIN32) || defined(__cplusplus)
# define __P(protos) protos
#else
# define __P(protos) ()
#endif
/* The structure used to return account information from the .netrc. */
typedef struct _netrc_entry {
/* The exact host name given in the .netrc, NULL if default. */
char *host;
/* The name of the account. */
char *account;
/* Password for the account (NULL, if none). */
char *password;
/* Pointer to the next entry in the list. */
struct _netrc_entry *next;
} netrc_entry;
__BEGIN_DECLS netrc_entry *parse_netrc __P((char *file));
netrc_entry *search_netrc __P((netrc_entry * list, const char *host));
__END_DECLS
#endif /* NETRC_H */

311
libprozilla/src/ping.c Normal file
View File

@@ -0,0 +1,311 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
#include "common.h"
#include "prozilla.h"
#include "connect.h"
#include "misc.h"
#include "url.h"
#include "netrc.h"
#include "debug.h"
#include "ping.h"
#define TCP_PING_PACKSIZE 3
uerr_t tcp_ping(ping_t * ping_data)
{
int status, noblock, flags;
extern int h_errno;
struct timeval start_time;
struct timeval end_time;
char ping_buf[TCP_PING_PACKSIZE];
int bytes_read;
struct addrinfo hints, *res=NULL;
char szPort[10];
int error;
assert(ping_data->host);
memset(&hints, 0, sizeof(hints));
memset(szPort, 0, sizeof(szPort));
snprintf(szPort, sizeof(szPort), "%d", ping_data->port);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(ping_data->host, szPort, &hints, &res);
if (error) {
return ping_data->err = HOSTERR;
}
if ((ping_data->sock = socket(res->ai_family, res->ai_socktype, IPPROTO_TCP)) < 1)
{
free(res);
return ping_data->err = CONSOCKERR;
}
/* Experimental. */
flags = fcntl(ping_data->sock, F_GETFL, 0);
if (flags != -1)
noblock = fcntl(ping_data->sock, F_SETFL, flags | O_NONBLOCK);
else
noblock = -1;
/* get start time */
gettimeofday(&start_time, 0);
status =
connect(ping_data->sock, res->ai_addr, res->ai_addrlen);
if ((status == -1) && (noblock != -1) && (errno == EINPROGRESS))
{
fd_set writefd;
FD_ZERO(&writefd);
FD_SET(ping_data->sock, &writefd);
status =
select((ping_data->sock + 1), NULL, &writefd, NULL,
&ping_data->timeout);
/* Do we need to retry if the err is EINTR? */
if (status > 0)
{
socklen_t arglen = sizeof(int);
if (getsockopt
(ping_data->sock, SOL_SOCKET, SO_ERROR, &status, &arglen) < 0)
status = errno;
if (status != 0)
errno = status, status = -1;
if (errno == EINPROGRESS)
errno = ETIMEDOUT;
} else if (status == 0)
errno = ETIMEDOUT, status = -1;
}
if (status < 0)
{
close_sock(&ping_data->sock);
if (errno == ECONNREFUSED)
{
free(res);
return ping_data->err = CONREFUSED;
} else if (errno == ETIMEDOUT)
{
free(res);
return ping_data->err = PINGTIMEOUT;
} else
{
free(res);
return ping_data->err = CONERROR;
}
} else
{
flags = fcntl(ping_data->sock, F_GETFL, 0);
if (flags != -1)
fcntl(ping_data->sock, F_SETFL, flags & ~O_NONBLOCK);
}
/* setsockopt(*sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt,
(int) sizeof(opt)); */
free(res);
/*So far so good connection established */
bytes_read =
krecv(ping_data->sock, ping_buf, TCP_PING_PACKSIZE, 0,
&ping_data->timeout);
close_sock(&ping_data->sock);
proz_debug("bytes read = %d", bytes_read);
if (bytes_read == -1)
{
if (errno == ETIMEDOUT)
return ping_data->err = PINGTIMEOUT;
else
return ping_data->err = READERR;
}
if (bytes_read == 0 || bytes_read < TCP_PING_PACKSIZE)
return ping_data->err = READERR;
/* the end time */
gettimeofday(&end_time, 0);
proz_timeval_subtract(&ping_data->ping_time, &end_time, &start_time);
/* standard_ping_milli_secs =(int)((((float)ping_data->ping_time.tv_usec/1000)+(((float)ping_data->ping_time.tv_sec)*1000))*3/(float)bytes_read);
ping_data->ping_time.tv_sec=standard_ping_milli_secs/1000;
ping_data->ping_time.tv_usec=standard_ping_milli_secs%1000;
*/
return ping_data->err = PINGOK;
}
void proz_mass_ping(ftps_request_t * request)
{
request->mass_ping_running = TRUE;
if (pthread_create(&request->mass_ping_thread, NULL,
(void *) &mass_ping, (void *) request) != 0)
proz_die(_("Error: Not enough system resources"));
}
void proz_cancel_mass_ping(ftps_request_t * request)
{
/*TODO Rewrite so that this will terminate the pingin threads as well */
request->mass_ping_running = FALSE;
pthread_cancel(request->mass_ping_thread);
pthread_join(request->mass_ping_thread,0);
}
void mass_ping(ftps_request_t * request)
{
int i, j, k = 0, num_iter, num_left, simul_pings;
pthread_t *ping_threads;
ping_t *ping_requests;
simul_pings = request->max_simul_pings;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
ping_threads = (pthread_t *) kmalloc(sizeof(pthread_t) * simul_pings);
ping_requests = kmalloc(sizeof(ping_t) * request->num_mirrors);
num_iter = request->num_mirrors / simul_pings;
num_left = request->num_mirrors % simul_pings;
proz_debug("Max simul pings=%d", simul_pings);
proz_debug("request->num_mirrors=%d", request->num_mirrors);
pthread_mutex_lock(&request->access_mutex);
request->mass_ping_running = TRUE;
pthread_mutex_unlock(&request->access_mutex);
k = 0;
for (i = 0; i < num_iter; i++)
{
for (j = 0; j < simul_pings; j++)
{
ping_t ping_request;
memset(ping_requests + k, 0, sizeof(ping_request));
/*FIXME */
ping_requests[k].timeout.tv_sec = request->ping_timeout.tv_sec;
ping_requests[k].timeout.tv_usec = request->ping_timeout.tv_usec;
ping_requests[k].host = strdup(request->mirrors[k].server_name);
ping_requests[k].port = 21;
if (pthread_create(&ping_threads[j], NULL,
(void *) &tcp_ping,
(void *) (ping_requests + k)) != 0)
proz_die("Error: Not enough system resources"
"to create thread!\n");
k++;
}
k -= simul_pings;
for (j = 0; j < simul_pings; j++)
{
/*Wait till the end of each thread. */
pthread_join(ping_threads[j], NULL);
if (ping_requests[k].err == PINGOK)
{
pthread_mutex_lock(&request->access_mutex);
request->mirrors[k].milli_secs =
(ping_requests[k].ping_time.tv_sec * 1000) +
(ping_requests[k].ping_time.tv_usec / 1000);
request->mirrors[k].status = RESPONSEOK;
pthread_mutex_unlock(&request->access_mutex);
} else
{
pthread_mutex_lock(&request->access_mutex);
request->mirrors[k].status = NORESPONSE;
pthread_mutex_unlock(&request->access_mutex);
}
k++;
}
}
for (j = 0; j < num_left; j++)
{
ping_t ping_request;
memset(ping_requests + k, 0, sizeof(ping_request));
/*FIXME */
ping_requests[k].timeout.tv_sec = request->ping_timeout.tv_sec;
ping_requests[k].timeout.tv_usec = 0;
ping_requests[k].host = strdup(request->mirrors[k].server_name);
ping_requests[k].port = 21;
if (pthread_create(&ping_threads[j], NULL,
(void *) &tcp_ping,
(void *) (&ping_requests[k])) != 0)
proz_die("Error: Not enough system resources" "to create thread!\n");
k++;
}
k -= num_left;
for (j = 0; j < num_left; j++)
{
/*Wait till the end of each thread. */
pthread_join(ping_threads[j], NULL);
/*Wait till the end of each thread. */
pthread_join(ping_threads[j], NULL);
if (ping_requests[k].err == PINGOK)
{
pthread_mutex_lock(&request->access_mutex);
request->mirrors[k].milli_secs =
(ping_requests[k].ping_time.tv_sec * 1000) +
(ping_requests[k].ping_time.tv_usec / 1000);
request->mirrors[k].status = RESPONSEOK;
pthread_mutex_unlock(&request->access_mutex);
} else
{
pthread_mutex_lock(&request->access_mutex);
request->mirrors[k].status = NORESPONSE;
pthread_mutex_unlock(&request->access_mutex);
}
k++;
}
proz_debug("mass_ping complete.");
pthread_mutex_lock(&request->access_mutex);
request->mass_ping_running = FALSE;
pthread_mutex_unlock(&request->access_mutex);
}

31
libprozilla/src/ping.h Normal file
View File

@@ -0,0 +1,31 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
#ifndef PING_H
#define PING_H
#include "common.h"
#include "prozilla.h"
uerr_t tcp_ping(ping_t * ping_info);
void mass_ping(ftps_request_t * request);
#endif

571
libprozilla/src/prozilla.h Normal file
View File

@@ -0,0 +1,571 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* Main include-file. */
/* $Id: prozilla.h,v 1.63 2005/09/19 15:25:48 kalum Exp $ */
#ifndef PROZILLA_H
#define PROZILLA_H
#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>
#include "netrc.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
/*Connect establishment related values */
NOCONERROR, HOSTERR, CONSOCKERR, CONERROR,
CONREFUSED, ACCEPTERR, ACCEPTOK, BINDERR, BINDOK, LISTENERR, LISTENOK,
SERVERCLOSECONERR, CONPORTERR,
/* URL handling related value */
URLOK, URLHTTP, URLFTP, URLFILE, URLUNKNOWN, URLBADPORT,
URLBADHOST, URLBADPATTERN,
/* HTTP related values */
NEWLOCATION, HOK, HEOF, HERR, HAUTHREQ, HAUTHFAIL,
HTTPNSFOD,
/*FTP related value */
FTPOK, FTPLOGINC, FTPLOGREFUSED, FTPPORTERR,
FTPNSFOD, FTPRETROK, FTPUNKNOWNTYPE, FTPUNKNOWNCMD, FTPSIZEFAIL,
FTPERR, FTPRESTFAIL, FTPACCDENIED,
FTPPWDERR,
FTPINVPASV, FTPNOPASV, FTPCONREFUSED, FTPCWDFAIL, FTPPWDFAIL,
FTPSERVCLOSEDATLOGIN,
/*FTP parsing related values */
FTPPARSEOK, FTPPARSENOTEXIST, FTPPARSEFAIL,
/*Error values that can happen due to failed proxie request */
GATEWAYTIMEOUT, SERVICEUNAVAIL, BADGATEWAY, INTERNALSERVERR,
UNKNOWNREQ,
/*File handling related return values. */
FOPENERR, FWRITEERR,
RETROK,
/*Download related retrn values. */
DLINPROGRESS, DLABORTED, DLDONE, CANTRESUME, DLLOCALFATAL,
DLREMOTEFATAL,
/*FTPSEARCH+ping related return values. */
FTPSINPROGRESS, MASSPINGINPROGRESS, FTPSFAIL, MASSPINGDONE,
/*PING related values */
PINGOK, PINGTIMEOUT,
/*Misc Value */
RETRFINISHED, READERR,
PROXERR, WRITEERR,
FILEISDIR,
MIRINFOK, MIRPARSEOK, MIRPARSEFAIL, FILEGETOK,
/*Related to file joining */
JOININPROGRESS, JOINDONE, JOINERR
} uerr_t;
#define FTP_BUFFER_SIZE 2048
#define HTTP_BUFFER_SIZE 2048
#define MAX_MSG_SIZE 1024
#define DEFAULT_FTP_PORT 21
#define DEFAULT_HTTP_PORT 80
/* This is used when no password is found or specified. */
#define DEFAULT_FTP_USER "anonymous"
#define DEFAULT_FTP_PASSWD "billg@hotmail.com"
/* The D/L ed fragments will be saved to files with this extension.
* E.g.: gnu.jpg.prz0, gnu.jpg.prz1 etc... */
#define DEFAULT_FILE_EXT ".prz"
/* The extension for the log file created. */
#define DEFAULT_LOG_EXT ".log"
#define DEFAULT_USER_AGENT "Prozilla"
typedef char longstring[1024];
/* Callback message function. */
typedef void (*message_proc) (const char *msg, void *cb_data);
/* Structure containing info on a URL. */
typedef struct _urlinfo {
char *url; /* Unchanged URL. */
uerr_t proto; /* URL protocol. */
char *host; /* Extracted hostname. */
unsigned short port;
char ftp_type;
char *path, *dir, *file; /* Path, dir and file (properly decoded). */
char *user, *passwd; /* For FTP. */
char *referer; /* The source from which the request
URI was obtained. */
} urlinfo;
typedef enum {
USERatSITE,
USERatPROXYUSERatSITE,
USERatSITE_PROXYUSER,
PROXYUSERatSITE,
LOGINthenUSERatSITE,
OPENSITE,
SITESITE,
HTTPPROXY,
FTPGATE,
WINGATE
} proxy_type;
typedef enum {
IDLE = 0,
CONNECTING,
LOGGININ,
DOWNLOADING,
COMPLETED,
LOGINFAIL,
CONREJECT,
REMOTEFATAL,
LOCALFATAL,
TIMEDOUT,
MAXTRYS
} dl_status;
typedef enum {
NOT_FOUND,
REGULAR_FILE,
DIRECTORY,
SYMBOLIC_LINK,
UNKNOWN
} file_type_t;
typedef struct {
off_t len; /* Received length. */
off_t contlen; /* Expected length. */
int res; /* The result of last read. */
/* -1 = Accept ranges not found.
0 = Accepts range is none.
1 = Accepts ranges. */
int accept_ranges;
char *newloc; /* New location (redirection). */
char *remote_time; /* Remote time-stamp string. */
char *error; /* Textual HTTP error. */
int statcode; /* Status code. */
} http_stat_t;
typedef struct {
urlinfo proxy_url;
char *username;
char *passwd;
proxy_type type;
boolean use_proxy;
} proxy_info;
typedef struct libprozinfo {
int argc;
char **argv;
boolean debug_mode;
/* For netrc. */
netrc_entry *netrc_list;
boolean use_netrc;
char *home_dir;
char *ftp_default_user;
char *ftp_default_passwd;
char *dl_dir;
char *output_dir;
char *log_dir;
boolean ftp_use_pasv;
proxy_info *ftp_proxy;
proxy_info *http_proxy;
boolean http_no_cache;
/* the default timeout for all the connection types (ctrl, data etc) */
struct timeval conn_timeout;
struct timeval conn_retry_delay;
int max_attempts;
long max_bps_per_dl;
} libprozinfo;
extern libprozinfo libprozrtinfo;
typedef struct response_line {
char *line;
struct response_line *next;
} response_line;
typedef struct connection_t {
/* struct which contains the parsed url info. It includes the remote file,
path,protocol etc. */
urlinfo u;
/* The error status of the connection. */
uerr_t err;
/* Proxy specific info. */
proxy_info *ftp_proxy;
proxy_info *http_proxy;
/* Netrc. */
boolean use_netrc;
/* FTP specific info. */
boolean ftp_use_pasv;
struct timeval xfer_timeout;
struct timeval conn_timeout;
struct timeval ctrl_timeout;
unsigned char pasv_addr[6];
int ctrl_sock;
int data_sock;
int listen_sock;
/* Additional info about what this URL is. */
/* FIXME Should this be in the url_info struct? */
file_type_t file_type;
/* The lines that the server returned. */
response_line *serv_ret_lines;
/* Does the server support resume? */
boolean resume_support;
/* The file name to save the data to locally. */
char *localfile;
/* Pointer to file that we will be saving the data to locally. */
FILE *fp;
/* Tells whether to open the file for appending or for writing etc.
Used for adding resume support. */
char *file_mode;
/* FIXME Add an enum here to say whether run mode is resume or normal etc.
and remove the file mode. */
off_t remote_startpos;
off_t orig_remote_startpos;
off_t remote_endpos;
off_t remote_bytes_received;
off_t main_file_size;
/* The permanent base offset from the beginning of the file, put in
anticipation of making the threads download to a single file. */
off_t local_base_offset;
/* Indicates the startpos of the localfile. It is always 0 in normal mode
and can be any positive value in resume mode. */
off_t local_startpos;
/* The start position at the beginning of the download. */
off_t orig_local_startpos;
/* long bytes_xferred; */
dl_status status;
char *szBuffer;
/* Tells the download thread whether to abort the download or not. */
boolean abort;
/* Information about the connection's start and end time. */
struct timeval time_begin;
struct timeval time_end;
/* Info about whether to retry the thread or not. */
boolean retry;
/* The number of attempts to try to complete a connection. 0 means unlimited
connection attempts. */
int max_attempts;
/* The number of attempts that this connection has been tried */
int attempts;
/* The time when to try to restart the connection. */
struct timeval retry_delay;
/* Each connection will acquire this mutex before changing state. */
pthread_mutex_t *status_change_mutex;
/*This will be broadcast when the connection starts connecting */
pthread_cond_t connecting_cond;
/* User agent for HTTP. */
char *user_agent;
http_stat_t hs;
message_proc msg_proc;
/*additional callback data whcih is specified by the user
that is passed to msg_proc */
void *cb_data;
/* Indicates whether a conenction is running or not */
int running;
/*Mutex used to lock acesss to data in this struct
that is accesed/written by other threads */
pthread_mutex_t access_mutex;
/*This indicates that we should use the pragma no-cache directive for http proxies */
boolean http_no_cache;
/*The rate of this connection whcih is calcualted */
long rate_bps;
/*We limit the connections speed to this */
long max_allowed_bps;
} connection_t;
typedef enum {
UNTESTED = 0, RESPONSEOK, NORESPONSE, ERROR
} ftp_mirror_stat_t;
typedef enum {
LYCOS, FILESEARCH_RU
} ftpsearch_server_type_t;
typedef struct {
char *path;
boolean valid;
} mirror_path_t;
typedef struct ftp_mirror {
char *server_name;
mirror_path_t *paths;
char *file_name;
char *full_name;
char *file_size;
struct timeval tv;
int milli_secs;
int num_paths;
ftp_mirror_stat_t status;
int copied;
boolean resume_supported;
int max_simul_connections;
} ftp_mirror_t;
typedef struct {
off_t file_size;
char *file_name;
connection_t *connection;
ftpsearch_server_type_t server_type;
ftp_mirror_t *mirrors;
int num_mirrors;
uerr_t err;
boolean info_running;
boolean mass_ping_running;
pthread_mutex_t access_mutex;
pthread_t info_thread;
pthread_t mass_ping_thread;
int max_simul_pings;
struct timeval ping_timeout;
urlinfo *requested_url;
} ftps_request_t;
typedef struct download_t {
urlinfo u;
char *dl_dir;
char *log_dir;
char *output_dir;
connection_t **pconnections;
pthread_t *threads;
pthread_mutex_t status_change_mutex;
int num_connections;
/* Optional will be called back with info about download. */
message_proc msg_proc;
/*additional callback data which is specified by the user
that is passed to msg_proc */
void *cb_data;
off_t main_file_size;
boolean resume_mode;
struct timeval start_time;
/*Does this DL support resume? */
boolean resume_support;
/*This contains the building status, 1 = building,0 build finished, -1 error occured */
int building;
/*This is the percentage of the file that is been built currently */
float file_build_percentage;
int max_simul_connections;
/*Mutex used to lock acesss to data in this struct
that is accesed/written by other threads */
pthread_mutex_t access_mutex;
/* The message that is returned when the file build process is finished
*/
char *file_build_msg;
/*Max mps for this download */
long max_allowed_bps;
ftps_request_t *ftps_info;
boolean using_ftpsearch;
pthread_t join_thread;
} download_t;
typedef struct {
/* the number of connections that this download was started with */
int num_connections;
/*I have added these newly */
int version; /*The version of this logfile */
/*Indicates whether we have got info about the files size, final URL etc */
boolean got_info;
off_t file_size;
int url_len; /*The length in bytes of the url text stred in the log file */
char *url;
int reserved[30];
} logfile;
/*Structs for logfile handling */
typedef struct {
char *host;
int port;
struct timeval timeout;
struct timeval ping_time;
int sock;
uerr_t err;
} ping_t;
/*Functions for URL parsing */
uerr_t proz_parse_url(const char *url, urlinfo * u, boolean strict);
urlinfo *proz_copy_url(urlinfo * u);
void proz_free_url(urlinfo * u, boolean complete);
/*Functions that set values which will apply for all conenctions. */
int proz_init(int argc, char **argv);
void proz_shutdown(void);
void proz_die(const char *message, ...);
void proz_set_http_proxy(proxy_info * proxy);
void proz_set_ftp_proxy(proxy_info * proxy);
void proz_use_ftp_proxy(boolean use);
void proz_use_http_proxy(boolean use);
void proz_set_connection_timeout(struct timeval *timeout);
void proz_set_connection_retry_delay(struct timeval *delay);
void proz_set_download_dir(char *dir);
void proz_set_logfile_dir(char *dir);
void proz_set_output_dir(char *dir);
char *proz_get_libprozilla_version();
/*Functions for loggind debug messages */
void proz_debug(const char *format, ...);
void proz_debug_delete_log();
/*Functions which are for handling a single connection. */
connection_t * proz_connection_init(urlinfo * url, pthread_mutex_t * mutex);
void proz_connection_set_url(connection_t * connection, urlinfo *url);
char *proz_connection_get_status_string(connection_t * connection);
off_t proz_connection_get_total_bytes_got(connection_t * connection);
void proz_get_url_info_loop(connection_t * connection, pthread_t *thread);
off_t proz_connection_get_total_remote_bytes_got(connection_t *
connection);
void proz_connection_set_msg_proc(connection_t * connection,
message_proc msg_proc, void *cb_data);
void proz_connection_free_connection(connection_t * connection,
boolean complete);
dl_status proz_connection_get_status(connection_t * connection);
boolean proz_connection_running(connection_t * connection);
/*Functions which are for handling a download */
download_t *proz_download_init(urlinfo * u);
int proz_download_setup_connections_no_ftpsearch(download_t * download,
connection_t *
connection,
int req_connections);
void proz_download_start_downloads(download_t * download,
boolean resume);
int proz_download_load_resume_info(download_t * download);
void proz_download_stop_downloads(download_t * download);
boolean proz_download_all_dls_status(download_t * download,
dl_status status);
boolean proz_download_all_dls_err(download_t * download, uerr_t err);
boolean proz_download_all_dls_filensfod(download_t * download);
boolean proz_download_all_dls_ftpcwdfail(download_t * download);
off_t proz_download_get_total_bytes_got(download_t * download);
uerr_t proz_download_handle_threads(download_t * download);
int proz_download_prev_download_exists(download_t * download);
float proz_download_get_average_speed(download_t * download);
int proz_download_delete_dl_file(download_t * download);
void proz_download_wait_till_all_end(download_t * download);
off_t proz_download_get_total_remote_bytes_got(download_t * download);
void proz_download_set_msg_proc(download_t * download,
message_proc msg_proc, void *cb_data);
off_t proz_download_get_est_time_left(download_t * download);
void proz_download_free_download(download_t * download,
boolean complete);
int proz_download_target_exist(download_t * download);
int proz_download_delete_target(download_t * download);
/* Functions related to handling the logfile created for a download */
int proz_log_read_logfile(logfile * lf, download_t * download,
boolean load_con_info);
int proz_log_delete_logfile(download_t * download);
int proz_log_logfile_exists(download_t * download);
char *proz_strerror(uerr_t error);
/*Ftpsearch releated */
ftps_request_t * proz_ftps_request_init(
urlinfo * requested_url, off_t file_size,
char *ftps_loc,
ftpsearch_server_type_t server_type,
int num_req_mirrors);
void proz_get_complete_mirror_list(ftps_request_t * request);
boolean proz_request_info_running(ftps_request_t * request);
boolean proz_request_mass_ping_running(ftps_request_t * request);
void proz_mass_ping(ftps_request_t * request);
void proz_sort_mirror_list(ftp_mirror_t * mirrors, int num_servers);
void proz_cancel_mirror_list_request(ftps_request_t * request);
int proz_download_setup_connections_ftpsearch(download_t * download,
connection_t * connection,
ftps_request_t * request,
int req_connections);
void proz_cancel_mass_ping(ftps_request_t * request);
/*Misc functions */
int proz_timeval_subtract(struct timeval *result, struct timeval *x,
struct timeval *y);
/*Funcs related to joining the downloaded file portions */
void proz_download_join_downloads(download_t * download);
uerr_t proz_download_get_join_status(download_t *download);
float proz_download_get_file_build_percentage(download_t *download);
void proz_download_cancel_joining_thread(download_t * download);
void proz_download_wait_till_end_joining_thread(download_t * download);
#ifdef __cplusplus
}
#endif
#endif /* PROZILLA_H */

70
libprozilla/src/test.c Normal file
View File

@@ -0,0 +1,70 @@
/******************************************************************************
libprozilla - a download accelerator library
Copyright (C) 2001 Kalum Somaratna
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
/* A test program. */
/* $Id: test.c,v 1.30 2001/09/23 01:39:16 kalum Exp $ */
#include "common.h"
#include "prozilla.h"
#include "connection.h"
#include "misc.h"
#include "connect.h"
#include "ftp.h"
#include "http.h"
#include "download.h"
#include "ftpsearch.h"
#include "ping.h"
/******************************************************************************
The main function.
******************************************************************************/
int main(int argc, char **argv)
{
uerr_t err;
connection_t *connection;
ftps_request_t request;
struct timeval timeout, ping_time;
int i, j;
proz_init(argc, argv);
libprozrtinfo.conn_timeout.tv_sec = 100;
proz_prepare_ftps_request(&request, "ddd-3.3.tar.bz2", 4811576,
"http://ftpsearch.uniovi.es:8000/ftpsearch",
LYCOS, 40);
proz_get_complete_mirror_list(&request);
for (i = 0; i < request.num_mirrors; i++)
{
printf("%s\n", request.mirrors[i].server_name);
printf("\t%d\n", request.mirrors[i].num_paths);
for (j = 0; j < request.mirrors[i].num_paths; j++)
printf("\t\t%s\n", request.mirrors[i].paths[j].path);
}
timeout.tv_sec = 5;
timeout.tv_usec = 0;
proz_shutdown();
exit(EXIT_SUCCESS);
}

1138
libprozilla/src/url.c Normal file

File diff suppressed because it is too large Load Diff

74
libprozilla/src/url.h Normal file
View File

@@ -0,0 +1,74 @@
/* Declarations for URL handling.
Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* $Id: url.h,v 1.20 2001/08/17 21:53:39 kalum Exp $ */
#ifndef URL_H
#define URL_H
#include "common.h"
#include "misc.h"
#include "prozilla.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Structure containing info on a protocol. */
typedef struct proto {
char *name;
uerr_t ind;
unsigned short port;
} proto_t;
enum uflags {
URELATIVE = 0x0001, /* Is URL relative? */
UNOPROTO = 0x0002, /* Is URL without a protocol? */
UABS2REL = 0x0004, /* Convert absolute to relative? */
UREL2ABS = 0x0008 /* Convert relative to absolute? */
};
/* A structure that defines the whereabouts of a URL, i.e. its
position in an HTML document, etc. */
typedef struct _urlpos {
char *url; /* URL */
char *local_name; /* Local file to which it was saved. */
enum uflags flags; /* Various flags. */
int pos, size; /* Rekative position in the buffer. */
struct _urlpos *next; /* Next struct in list. */
} urlpos;
int
has_proto(const char *url);
int
skip_uname(const char *url);
void
parse_dir(const char *path, char **dir, char **file);
void
path_simplify(char *path);
char *uri_merge(const char *base, const char *link);
int
urlpath_length(const char *url);
int
skip_proto(const char *url);
char *str_url(const urlinfo * u, int hide);
#ifdef __cplusplus
}
#endif
#endif /* URL_H */