summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog72
-rw-r--r--Makefile.in3
-rw-r--r--TODO3
-rw-r--r--aclocal.m4189
-rw-r--r--config.h.in6
-rwxr-xr-xconfigure340
-rw-r--r--configure.ac12
-rw-r--r--m4/Makefile.in3
-rw-r--r--src/AbstractCommand.cc11
-rw-r--r--src/AbstractCommand.h1
-rw-r--r--src/AbstractDiskWriter.cc13
-rw-r--r--src/Base64.cc95
-rw-r--r--src/Base64.h9
-rw-r--r--src/Makefile.am11
-rw-r--r--src/Makefile.in22
-rw-r--r--src/MetalinkEntry.cc81
-rw-r--r--src/MetalinkEntry.h55
-rw-r--r--src/MetalinkProcessor.h35
-rw-r--r--src/MetalinkResource.cc26
-rw-r--r--src/MetalinkResource.h47
-rw-r--r--src/Metalinker.cc74
-rw-r--r--src/Metalinker.h46
-rw-r--r--src/MultiDiskWriter.cc13
-rw-r--r--src/PeerConnection.cc4
-rw-r--r--src/PeerMessageUtil.cc3
-rw-r--r--src/PieceMessage.cc1
-rw-r--r--src/Request.h2
-rw-r--r--src/SegmentMan.h2
-rw-r--r--src/ShaVisitor.cc33
-rw-r--r--src/Util.cc80
-rw-r--r--src/Util.h12
-rw-r--r--src/Xml2MetalinkProcessor.cc188
-rw-r--r--src/Xml2MetalinkProcessor.h51
-rw-r--r--src/main.cc180
-rw-r--r--src/messageDigest.h81
-rw-r--r--test/Base64Test.cc8
-rw-r--r--test/Makefile.am9
-rw-r--r--test/Makefile.in19
-rw-r--r--test/UtilTest.cc34
39 files changed, 1721 insertions, 153 deletions
diff --git a/ChangeLog b/ChangeLog
index 8d6f6b68..d6b0ac1f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,75 @@
+2006-07-03 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
+
+ To add Metalink support(http/ftp only):
+
+ * src/AbstractCommand.h
+ (tryReserved): New function.
+ * src/AbstractCommand.cc
+ (execute): Call tryReserved().
+ (tryReserved): New function.
+ * src/Request.h
+ (Requests): New type definition.
+ * src/SegmentMan.h
+ (reserved): New variable.
+ * src/Util.h
+ (fileChecksum): New function.
+ (toUpper): New function.
+ (toLower): New function.
+ * src/Util.cc
+ (messageDigest.h): Included.
+ (trim): Trim \r\n\t.
+ (fileChecksum): New function.
+ (toUpper): New function.
+ (toLower): New function.
+ * src/main.cc
+ (normalDownload): New function.
+ (main): Added 2 command-line options: metalink-file,
+ metalink-connection. Their usage has not been written yet.
+ * src/MetalinkProcessor.h: New class.
+ * src/Xml2MetalinkProcessor.h: New class.
+ * src/Xml2MetalinkProcessor.cc: New class.
+ * src/MetalinkEntry.h: New class.
+ * src/MetalinkEntry.cc: New class.
+ * src/MetalinkResource.h: New class.
+ * src/MetalinkResource.cc: New class.
+
+ To add md5 message digest checking:
+
+ * src/messageDigest.h: Rewritten.
+ * src/MultiDiskWriter.cc: Updated according to the changes in
+ messageDigest.h.
+ * src/ShaVisitor.cc: Updated according to the changes in
+ messageDigest.h.
+ * src/Util.cc: Updated according to the changes in messageDigest.h.
+ * src/AbstractDiskWriter.cc: Updated according to the changes in
+ messageDigest.h.
+
+ To fix a bug that causes segfault when the payload length in peer
+ message is less than 0:
+
+ * src/PeerConnection.cc:
+ (receiveMessage): Fixed the bug.
+ * src/PeerMessageUtil.cc
+ (checkLength): Throw an exception if length is less than or equals to
+ 0.
+
+ To add new interfaces to Base64 encoding/decoding:
+
+ * src/Base64.h
+ (part_encode): Changed the method signature.
+ (encode): New function(overload).
+ (decode): New function(overload).
+ * src/Base64.cc
+ (part_encode): Rewritten.
+ (encode): Rewritten.
+ (encode): New function(overload).
+
+ To prevent a peer to download same piece if there is an error in
+ checksum:
+
+ * src/PieceMessage.cc
+ (receivedAction): Call peerInteraction->abortPiece().
+
2006-06-25 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
To fix the bug that causes same have message is sent many times to
diff --git a/Makefile.in b/Makefile.in
index 3c23e9dc..7375f735 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -163,6 +163,9 @@ USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
XGETTEXT = @XGETTEXT@
+XML2_CONFIG = @XML2_CONFIG@
+XML_CPPFLAGS = @XML_CPPFLAGS@
+XML_LIBS = @XML_LIBS@
YACC = @YACC@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
diff --git a/TODO b/TODO
index 9d56f738..3a7fcb11 100644
--- a/TODO
+++ b/TODO
@@ -14,3 +14,6 @@
* Add Mainline-compatible DHT support
* Add Message stream encryption support
* Refacturing HttpConnection and FtpConnection
+* Use EXIT_SUCCESS and EXIT_FAILURE
+* Query resource by location
+* Conditional compilation based on ENABLE_LIBXML2 \ No newline at end of file
diff --git a/aclocal.m4 b/aclocal.m4
index c51bf07b..7c96ff90 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -362,6 +362,195 @@ main ()
dnl *-*wedit:notab*-* Please keep this as the last line.
+# Configure paths for LIBXML2
+# Mike Hommey 2004-06-19
+# use CPPFLAGS instead of CFLAGS
+# Toshio Kuratomi 2001-04-21
+# Adapted from:
+# Configure paths for GLIB
+# Owen Taylor 97-11-3
+
+dnl AM_PATH_XML2([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for XML, and define XML_CPPFLAGS and XML_LIBS
+dnl
+AC_DEFUN([AM_PATH_XML2],[
+AC_ARG_WITH(xml-prefix,
+ [ --with-xml-prefix=PFX Prefix where libxml is installed (optional)],
+ xml_config_prefix="$withval", xml_config_prefix="")
+AC_ARG_WITH(xml-exec-prefix,
+ [ --with-xml-exec-prefix=PFX Exec prefix where libxml is installed (optional)],
+ xml_config_exec_prefix="$withval", xml_config_exec_prefix="")
+AC_ARG_ENABLE(xmltest,
+ [ --disable-xmltest Do not try to compile and run a test LIBXML program],,
+ enable_xmltest=yes)
+
+ if test x$xml_config_exec_prefix != x ; then
+ xml_config_args="$xml_config_args"
+ if test x${XML2_CONFIG+set} != xset ; then
+ XML2_CONFIG=$xml_config_exec_prefix/bin/xml2-config
+ fi
+ fi
+ if test x$xml_config_prefix != x ; then
+ xml_config_args="$xml_config_args --prefix=$xml_config_prefix"
+ if test x${XML2_CONFIG+set} != xset ; then
+ XML2_CONFIG=$xml_config_prefix/bin/xml2-config
+ fi
+ fi
+
+ AC_PATH_PROG(XML2_CONFIG, xml2-config, no)
+ min_xml_version=ifelse([$1], ,2.0.0,[$1])
+ AC_MSG_CHECKING(for libxml - version >= $min_xml_version)
+ no_xml=""
+ if test "$XML2_CONFIG" = "no" ; then
+ no_xml=yes
+ else
+ XML_CPPFLAGS=`$XML2_CONFIG $xml_config_args --cflags`
+ XML_LIBS=`$XML2_CONFIG $xml_config_args --libs`
+ xml_config_major_version=`$XML2_CONFIG $xml_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ xml_config_minor_version=`$XML2_CONFIG $xml_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ xml_config_micro_version=`$XML2_CONFIG $xml_config_args --version | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+ if test "x$enable_xmltest" = "xyes" ; then
+ ac_save_CPPFLAGS="$CPPFLAGS"
+ ac_save_LIBS="$LIBS"
+ CPPFLAGS="$CPPFLAGS $XML_CPPFLAGS"
+ LIBS="$XML_LIBS $LIBS"
+dnl
+dnl Now check if the installed libxml is sufficiently new.
+dnl (Also sanity checks the results of xml2-config to some extent)
+dnl
+ rm -f conf.xmltest
+ AC_TRY_RUN([
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libxml/xmlversion.h>
+
+int
+main()
+{
+ int xml_major_version, xml_minor_version, xml_micro_version;
+ int major, minor, micro;
+ char *tmp_version;
+
+ system("touch conf.xmltest");
+
+ /* Capture xml2-config output via autoconf/configure variables */
+ /* HP/UX 9 (%@#!) writes to sscanf strings */
+ tmp_version = (char *)strdup("$min_xml_version");
+ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+ printf("%s, bad version string from xml2-config\n", "$min_xml_version");
+ exit(1);
+ }
+ free(tmp_version);
+
+ /* Capture the version information from the header files */
+ tmp_version = (char *)strdup(LIBXML_DOTTED_VERSION);
+ if (sscanf(tmp_version, "%d.%d.%d", &xml_major_version, &xml_minor_version, &xml_micro_version) != 3) {
+ printf("%s, bad version string from libxml includes\n", "LIBXML_DOTTED_VERSION");
+ exit(1);
+ }
+ free(tmp_version);
+
+ /* Compare xml2-config output to the libxml headers */
+ if ((xml_major_version != $xml_config_major_version) ||
+ (xml_minor_version != $xml_config_minor_version) ||
+ (xml_micro_version != $xml_config_micro_version))
+ {
+ printf("*** libxml header files (version %d.%d.%d) do not match\n",
+ xml_major_version, xml_minor_version, xml_micro_version);
+ printf("*** xml2-config (version %d.%d.%d)\n",
+ $xml_config_major_version, $xml_config_minor_version, $xml_config_micro_version);
+ return 1;
+ }
+/* Compare the headers to the library to make sure we match */
+ /* Less than ideal -- doesn't provide us with return value feedback,
+ * only exits if there's a serious mismatch between header and library.
+ */
+ LIBXML_TEST_VERSION;
+
+ /* Test that the library is greater than our minimum version */
+ if ((xml_major_version > major) ||
+ ((xml_major_version == major) && (xml_minor_version > minor)) ||
+ ((xml_major_version == major) && (xml_minor_version == minor) &&
+ (xml_micro_version >= micro)))
+ {
+ return 0;
+ }
+ else
+ {
+ printf("\n*** An old version of libxml (%d.%d.%d) was found.\n",
+ xml_major_version, xml_minor_version, xml_micro_version);
+ printf("*** You need a version of libxml newer than %d.%d.%d. The latest version of\n",
+ major, minor, micro);
+ printf("*** libxml is always available from ftp://ftp.xmlsoft.org.\n");
+ printf("***\n");
+ printf("*** If you have already installed a sufficiently new version, this error\n");
+ printf("*** probably means that the wrong copy of the xml2-config shell script is\n");
+ printf("*** being found. The easiest way to fix this is to remove the old version\n");
+ printf("*** of LIBXML, but you can also set the XML2_CONFIG environment to point to the\n");
+ printf("*** correct copy of xml2-config. (In this case, you will have to\n");
+ printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+ printf("*** so that the correct libraries are found at run-time))\n");
+ }
+ return 1;
+}
+],, no_xml=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+
+ if test "x$no_xml" = x ; then
+ AC_MSG_RESULT(yes (version $xml_config_major_version.$xml_config_minor_version.$xml_config_micro_version))
+ ifelse([$2], , :, [$2])
+ else
+ AC_MSG_RESULT(no)
+ if test "$XML2_CONFIG" = "no" ; then
+ echo "*** The xml2-config script installed by LIBXML could not be found"
+ echo "*** If libxml was installed in PREFIX, make sure PREFIX/bin is in"
+ echo "*** your path, or set the XML2_CONFIG environment variable to the"
+ echo "*** full path to xml2-config."
+ else
+ if test -f conf.xmltest ; then
+ :
+ else
+ echo "*** Could not run libxml test program, checking why..."
+ CPPFLAGS="$CPPFLAGS $XML_CPPFLAGS"
+ LIBS="$LIBS $XML_LIBS"
+ AC_TRY_LINK([
+#include <libxml/xmlversion.h>
+#include <stdio.h>
+], [ LIBXML_TEST_VERSION; return 0;],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding LIBXML or finding the wrong"
+ echo "*** version of LIBXML. If it is not finding LIBXML, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means LIBXML was incorrectly installed"
+ echo "*** or that you have moved LIBXML since it was installed. In the latter case, you"
+ echo "*** may want to edit the xml2-config script: $XML2_CONFIG" ])
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+
+ XML_CPPFLAGS=""
+ XML_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+ AC_SUBST(XML_CPPFLAGS)
+ AC_SUBST(XML_LIBS)
+ rm -f conf.xmltest
+])
+
# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
diff --git a/config.h.in b/config.h.in
index 54b7068b..a13a4822 100644
--- a/config.h.in
+++ b/config.h.in
@@ -11,6 +11,9 @@
/* Define to 1 if BitTorrent support is enabled. */
#undef ENABLE_BITTORRENT
+/* Define to 1 if Metalink support is enabled. */
+#undef ENABLE_METALINK
+
/* Define to 1 if translation of program messages to the user's native
language is requested. */
#undef ENABLE_NLS
@@ -114,6 +117,9 @@
/* Define to 1 if you have openssl. */
#undef HAVE_LIBSSL
+/* Define to 1 if you have libxml2. */
+#undef HAVE_LIBXML2
+
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
diff --git a/configure b/configure
index 5972f242..cf884209 100755
--- a/configure
+++ b/configure
@@ -311,7 +311,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CPPUNIT_CONFIG CPPUNIT_CFLAGS CPPUNIT_LIBS localedir CXX CXXFLAGS LDFLAGS CPPFLAGS ac_ct_CXX EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CC CFLAGS ac_ct_CC CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE RANLIB ac_ct_RANLIB YACC LIBGNUTLS_CONFIG LIBGNUTLS_CFLAGS LIBGNUTLS_LIBS LIBGCRYPT_CONFIG LIBGCRYPT_CFLAGS LIBGCRYPT_LIBS OPENSSL_LIBS OPENSSL_CFLAGS ALLOCA CPP EGREP MKINSTALLDIRS USE_NLS MSGFMT GMSGFMT XGETTEXT MSGMERGE build build_cpu build_vendor build_os host host_cpu host_vendor host_os GLIBC21 LIBICONV LTLIBICONV INTLBISON BUILD_INCLUDED_LIBINTL USE_INCLUDED_LIBINTL CATOBJEXT DATADIRNAME INSTOBJEXT GENCAT INTLOBJS INTL_LIBTOOL_SUFFIX_PREFIX INTLLIBS LIBINTL LTLIBINTL POSUB LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CPPUNIT_CONFIG CPPUNIT_CFLAGS CPPUNIT_LIBS localedir CXX CXXFLAGS LDFLAGS CPPFLAGS ac_ct_CXX EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CC CFLAGS ac_ct_CC CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE RANLIB ac_ct_RANLIB YACC XML2_CONFIG XML_CPPFLAGS XML_LIBS LIBGNUTLS_CONFIG LIBGNUTLS_CFLAGS LIBGNUTLS_LIBS LIBGCRYPT_CONFIG LIBGCRYPT_CFLAGS LIBGCRYPT_LIBS OPENSSL_LIBS OPENSSL_CFLAGS ALLOCA CPP EGREP MKINSTALLDIRS USE_NLS MSGFMT GMSGFMT XGETTEXT MSGMERGE build build_cpu build_vendor build_os host host_cpu host_vendor host_os GLIBC21 LIBICONV LTLIBICONV INTLBISON BUILD_INCLUDED_LIBINTL USE_INCLUDED_LIBINTL CATOBJEXT DATADIRNAME INSTOBJEXT GENCAT INTLOBJS INTL_LIBTOOL_SUFFIX_PREFIX INTLLIBS LIBINTL LTLIBINTL POSUB LIBOBJS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -863,6 +863,7 @@ Optional Features:
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--disable-dependency-tracking speeds up one-time build
--enable-dependency-tracking do not reject slow dependency extractors
+ --disable-xmltest Do not try to compile and run a test LIBXML program
--disable-nls do not use Native Language Support
--disable-rpath do not hardcode runtime library paths
@@ -873,6 +874,9 @@ Optional Packages:
--with-cppunit-exec-prefix=PFX Exec prefix where CppUnit is installed (optional)
--with-gnutls use gnutls library if installed. Default: yes
--with-openssl use openssl library if installed. Default: yes
+ --with-libxml2 use libxml2 library if installed. Default: yes
+ --with-xml-prefix=PFX Prefix where libxml is installed (optional)
+ --with-xml-exec-prefix=PFX Exec prefix where libxml is installed (optional)
--with-libgnutls-prefix=PFX Prefix where libgnutls is installed (optional)
--with-libgcrypt-prefix=PFX
prefix where LIBGCRYPT is installed (optional)
@@ -1934,6 +1938,14 @@ else
with_openssl=yes
fi;
+# Check whether --with-libxml2 or --without-libxml2 was given.
+if test "${with_libxml2+set}" = set; then
+ withval="$with_libxml2"
+ with_libxml2=$enableval
+else
+ with_libxml2=yes
+fi;
+
# Checks for programs.
ac_ext=cc
@@ -3696,8 +3708,321 @@ test -n "$YACC" || YACC="yacc"
# Checks for libraries.
-if test "x$with_gnutls" = "xyes"; then
+if test "x$with_libxml2" = "xyes"; then
+
+
+
+# Check whether --with-xml-prefix or --without-xml-prefix was given.
+if test "${with_xml_prefix+set}" = set; then
+ withval="$with_xml_prefix"
+ xml_config_prefix="$withval"
+else
+ xml_config_prefix=""
+fi;
+
+# Check whether --with-xml-exec-prefix or --without-xml-exec-prefix was given.
+if test "${with_xml_exec_prefix+set}" = set; then
+ withval="$with_xml_exec_prefix"
+ xml_config_exec_prefix="$withval"
+else
+ xml_config_exec_prefix=""
+fi;
+# Check whether --enable-xmltest or --disable-xmltest was given.
+if test "${enable_xmltest+set}" = set; then
+ enableval="$enable_xmltest"
+
+else
+ enable_xmltest=yes
+fi;
+
+ if test x$xml_config_exec_prefix != x ; then
+ xml_config_args="$xml_config_args"
+ if test x${XML2_CONFIG+set} != xset ; then
+ XML2_CONFIG=$xml_config_exec_prefix/bin/xml2-config
+ fi
+ fi
+ if test x$xml_config_prefix != x ; then
+ xml_config_args="$xml_config_args --prefix=$xml_config_prefix"
+ if test x${XML2_CONFIG+set} != xset ; then
+ XML2_CONFIG=$xml_config_prefix/bin/xml2-config
+ fi
+ fi
+
+ # Extract the first word of "xml2-config", so it can be a program name with args.
+set dummy xml2-config; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_XML2_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $XML2_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_XML2_CONFIG="$XML2_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_XML2_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+ test -z "$ac_cv_path_XML2_CONFIG" && ac_cv_path_XML2_CONFIG="no"
+ ;;
+esac
+fi
+XML2_CONFIG=$ac_cv_path_XML2_CONFIG
+
+if test -n "$XML2_CONFIG"; then
+ echo "$as_me:$LINENO: result: $XML2_CONFIG" >&5
+echo "${ECHO_T}$XML2_CONFIG" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ min_xml_version=2.6.26
+ echo "$as_me:$LINENO: checking for libxml - version >= $min_xml_version" >&5
+echo $ECHO_N "checking for libxml - version >= $min_xml_version... $ECHO_C" >&6
+ no_xml=""
+ if test "$XML2_CONFIG" = "no" ; then
+ no_xml=yes
+ else
+ XML_CPPFLAGS=`$XML2_CONFIG $xml_config_args --cflags`
+ XML_LIBS=`$XML2_CONFIG $xml_config_args --libs`
+ xml_config_major_version=`$XML2_CONFIG $xml_config_args --version | \
+ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'`
+ xml_config_minor_version=`$XML2_CONFIG $xml_config_args --version | \
+ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'`
+ xml_config_micro_version=`$XML2_CONFIG $xml_config_args --version | \
+ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'`
+ if test "x$enable_xmltest" = "xyes" ; then
+ ac_save_CPPFLAGS="$CPPFLAGS"
+ ac_save_LIBS="$LIBS"
+ CPPFLAGS="$CPPFLAGS $XML_CPPFLAGS"
+ LIBS="$XML_LIBS $LIBS"
+ rm -f conf.xmltest
+ if test "$cross_compiling" = yes; then
+ echo $ac_n "cross compiling; assumed OK... $ac_c"
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libxml/xmlversion.h>
+
+int
+main()
+{
+ int xml_major_version, xml_minor_version, xml_micro_version;
+ int major, minor, micro;
+ char *tmp_version;
+
+ system("touch conf.xmltest");
+
+ /* Capture xml2-config output via autoconf/configure variables */
+ /* HP/UX 9 (%@#!) writes to sscanf strings */
+ tmp_version = (char *)strdup("$min_xml_version");
+ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+ printf("%s, bad version string from xml2-config\n", "$min_xml_version");
+ exit(1);
+ }
+ free(tmp_version);
+
+ /* Capture the version information from the header files */
+ tmp_version = (char *)strdup(LIBXML_DOTTED_VERSION);
+ if (sscanf(tmp_version, "%d.%d.%d", &xml_major_version, &xml_minor_version, &xml_micro_version) != 3) {
+ printf("%s, bad version string from libxml includes\n", "LIBXML_DOTTED_VERSION");
+ exit(1);
+ }
+ free(tmp_version);
+
+ /* Compare xml2-config output to the libxml headers */
+ if ((xml_major_version != $xml_config_major_version) ||
+ (xml_minor_version != $xml_config_minor_version) ||
+ (xml_micro_version != $xml_config_micro_version))
+ {
+ printf("*** libxml header files (version %d.%d.%d) do not match\n",
+ xml_major_version, xml_minor_version, xml_micro_version);
+ printf("*** xml2-config (version %d.%d.%d)\n",
+ $xml_config_major_version, $xml_config_minor_version, $xml_config_micro_version);
+ return 1;
+ }
+/* Compare the headers to the library to make sure we match */
+ /* Less than ideal -- doesn't provide us with return value feedback,
+ * only exits if there's a serious mismatch between header and library.
+ */
+ LIBXML_TEST_VERSION;
+
+ /* Test that the library is greater than our minimum version */
+ if ((xml_major_version > major) ||
+ ((xml_major_version == major) && (xml_minor_version > minor)) ||
+ ((xml_major_version == major) && (xml_minor_version == minor) &&
+ (xml_micro_version >= micro)))
+ {
+ return 0;
+ }
+ else
+ {
+ printf("\n*** An old version of libxml (%d.%d.%d) was found.\n",
+ xml_major_version, xml_minor_version, xml_micro_version);
+ printf("*** You need a version of libxml newer than %d.%d.%d. The latest version of\n",
+ major, minor, micro);
+ printf("*** libxml is always available from ftp://ftp.xmlsoft.org.\n");
+ printf("***\n");
+ printf("*** If you have already installed a sufficiently new version, this error\n");
+ printf("*** probably means that the wrong copy of the xml2-config shell script is\n");
+ printf("*** being found. The easiest way to fix this is to remove the old version\n");
+ printf("*** of LIBXML, but you can also set the XML2_CONFIG environment to point to the\n");
+ printf("*** correct copy of xml2-config. (In this case, you will have to\n");
+ printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+ printf("*** so that the correct libraries are found at run-time))\n");
+ }
+ return 1;
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+no_xml=yes
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+
+ if test "x$no_xml" = x ; then
+ echo "$as_me:$LINENO: result: yes (version $xml_config_major_version.$xml_config_minor_version.$xml_config_micro_version)" >&5
+echo "${ECHO_T}yes (version $xml_config_major_version.$xml_config_minor_version.$xml_config_micro_version)" >&6
+ have_libxml2=yes
+ else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+ if test "$XML2_CONFIG" = "no" ; then
+ echo "*** The xml2-config script installed by LIBXML could not be found"
+ echo "*** If libxml was installed in PREFIX, make sure PREFIX/bin is in"
+ echo "*** your path, or set the XML2_CONFIG environment variable to the"
+ echo "*** full path to xml2-config."
+ else
+ if test -f conf.xmltest ; then
+ :
+ else
+ echo "*** Could not run libxml test program, checking why..."
+ CPPFLAGS="$CPPFLAGS $XML_CPPFLAGS"
+ LIBS="$LIBS $XML_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <libxml/xmlversion.h>
+#include <stdio.h>
+
+int
+main ()
+{
+ LIBXML_TEST_VERSION; return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding LIBXML or finding the wrong"
+ echo "*** version of LIBXML. If it is not finding LIBXML, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means LIBXML was incorrectly installed"
+ echo "*** or that you have moved LIBXML since it was installed. In the latter case, you"
+ echo "*** may want to edit the xml2-config script: $XML2_CONFIG"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ fi
+
+ XML_CPPFLAGS=""
+ XML_LIBS=""
+ :
+ fi
+
+
+ rm -f conf.xmltest
+
+ if test "x$have_libxml2" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LIBXML2 1
+_ACEOF
+
+ fi
+fi
+
+if test "x$with_gnutls" = "xyes"; then
# Check whether --with-libgnutls-prefix or --without-libgnutls-prefix was given.
if test "${with_libgnutls_prefix+set}" = set; then
@@ -4292,6 +4617,14 @@ CPPFLAGS=$CPPFLAGS_save
fi
+if test "x$have_libxml2" = "xyes"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define ENABLE_METALINK 1
+_ACEOF
+
+fi
+
if test "x$have_libgnutls" = "xyes" || test "x$have_openssl" = "xyes"; then
cat >>confdefs.h <<\_ACEOF
@@ -11853,6 +12186,9 @@ s,@am__fastdepCC_FALSE@,$am__fastdepCC_FALSE,;t t
s,@RANLIB@,$RANLIB,;t t
s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
s,@YACC@,$YACC,;t t
+s,@XML2_CONFIG@,$XML2_CONFIG,;t t
+s,@XML_CPPFLAGS@,$XML_CPPFLAGS,;t t
+s,@XML_LIBS@,$XML_LIBS,;t t
s,@LIBGNUTLS_CONFIG@,$LIBGNUTLS_CONFIG,;t t
s,@LIBGNUTLS_CFLAGS@,$LIBGNUTLS_CFLAGS,;t t
s,@LIBGNUTLS_LIBS@,$LIBGNUTLS_LIBS,;t t
diff --git a/configure.ac b/configure.ac
index 4e974144..840bef1b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -15,6 +15,7 @@ AC_SUBST(localedir)
# Checks for arguments.
AC_ARG_WITH([gnutls], [ --with-gnutls use gnutls library if installed. Default: yes], [with_gnutls=$enableval], [with_gnutls=yes])
AC_ARG_WITH([openssl], [ --with-openssl use openssl library if installed. Default: yes], [with_openssl=$enableval], [with_openssl=yes])
+AC_ARG_WITH([libxml2], [ --with-libxml2 use libxml2 library if installed. Default: yes], [with_libxml2=$enableval], [with_libxml2=yes])
# Checks for programs.
@@ -25,6 +26,13 @@ AC_PROG_RANLIB
AC_PROG_YACC
# Checks for libraries.
+if test "x$with_libxml2" = "xyes"; then
+ AM_PATH_XML2([2.6.26], [have_libxml2=yes])
+ if test "x$have_libxml2" = "xyes"; then
+ AC_DEFINE([HAVE_LIBXML2], [1], [Define to 1 if you have libxml2.])
+ fi
+fi
+
if test "x$with_gnutls" = "xyes"; then
AM_PATH_LIBGNUTLS([1.2.9], [have_libgnutls=yes])
if test "x$have_libgnutls" = "xyes"; then
@@ -51,6 +59,10 @@ if test "x$with_openssl" = "xyes" && test "x$have_libgnutls" != "xyes"; then
AM_PATH_OPENSSL
fi
+if test "x$have_libxml2" = "xyes"; then
+ AC_DEFINE([ENABLE_METALINK], [1], [Define to 1 if Metalink support is enabled.])
+fi
+
if test "x$have_libgnutls" = "xyes" || test "x$have_openssl" = "xyes"; then
AC_DEFINE([ENABLE_SSL], [1], [Define to 1 if ssl support is enabled.])
fi
diff --git a/m4/Makefile.in b/m4/Makefile.in
index e286bf15..fa7a7484 100644
--- a/m4/Makefile.in
+++ b/m4/Makefile.in
@@ -137,6 +137,9 @@ USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
XGETTEXT = @XGETTEXT@
+XML2_CONFIG = @XML2_CONFIG@
+XML_CPPFLAGS = @XML_CPPFLAGS@
+XML_LIBS = @XML_LIBS@
YACC = @YACC@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
diff --git a/src/AbstractCommand.cc b/src/AbstractCommand.cc
index 0de96354..a622959a 100644
--- a/src/AbstractCommand.cc
+++ b/src/AbstractCommand.cc
@@ -77,6 +77,7 @@ bool AbstractCommand::execute() {
delete(err);
req->resetUrl();
e->segmentMan->errors++;
+ tryReserved();
return true;
} catch(DlRetryEx* err) {
logger->error(MSG_RESTARTING_DOWNLOAD, err, cuid);
@@ -90,6 +91,7 @@ bool AbstractCommand::execute() {
if(isAbort) {
logger->error(MSG_MAX_TRY, cuid, req->getTryCount());
e->segmentMan->errors++;
+ tryReserved();
return true;
} else {
return prepareForRetry(e->option->getAsInt(PREF_RETRY_WAIT));
@@ -97,6 +99,15 @@ bool AbstractCommand::execute() {
}
}
+void AbstractCommand::tryReserved() {
+ if(!e->segmentMan->reserved.empty()) {
+ Request* req = e->segmentMan->reserved.front();
+ e->segmentMan->reserved.pop_front();
+ Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, req, e);
+ e->commands.push_back(command);
+ }
+}
+
bool AbstractCommand::prepareForRetry(int wait) {
Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, req, e);
if(wait == 0) {
diff --git a/src/AbstractCommand.h b/src/AbstractCommand.h
index c4b3d91f..6eb6e9f4 100644
--- a/src/AbstractCommand.h
+++ b/src/AbstractCommand.h
@@ -37,6 +37,7 @@ protected:
DownloadEngine* e;
Socket* socket;
+ void tryReserved();
virtual bool prepareForRetry(int wait);
virtual void onAbort(Exception* ex);
virtual bool executeInternal(Segment segment) = 0;
diff --git a/src/AbstractDiskWriter.cc b/src/AbstractDiskWriter.cc
index 42f23b03..f249b274 100644
--- a/src/AbstractDiskWriter.cc
+++ b/src/AbstractDiskWriter.cc
@@ -32,14 +32,15 @@
AbstractDiskWriter::AbstractDiskWriter():fd(0) {
#ifdef ENABLE_SHA1DIGEST
- sha1DigestInit(ctx);
+ ctx.setAlgo(MessageDigestContext::ALGO_SHA1);
+ digestInit(ctx);
#endif // ENABLE_SHA1DIGEST
}
AbstractDiskWriter::~AbstractDiskWriter() {
closeFile();
#ifdef ENABLE_SHA1DIGEST
- sha1DigestFree(ctx);
+ digestFree(ctx);
#endif // ENABLE_SHA1DIGEST
}
@@ -99,7 +100,7 @@ int AbstractDiskWriter::readDataInternal(char* data, int len) {
string AbstractDiskWriter::sha1Sum(long long int offset, long long int length) {
#ifdef ENABLE_SHA1DIGEST
- sha1DigestReset(ctx);
+ digestReset(ctx);
try {
int BUFSIZE = 16*1024;
char buf[BUFSIZE];
@@ -107,7 +108,7 @@ string AbstractDiskWriter::sha1Sum(long long int offset, long long int length) {
if(BUFSIZE != readData(buf, BUFSIZE, offset)) {
throw string("error");
}
- sha1DigestUpdate(ctx, buf, BUFSIZE);
+ digestUpdate(ctx, buf, BUFSIZE);
offset += BUFSIZE;
}
int r = length%BUFSIZE;
@@ -115,10 +116,10 @@ string AbstractDiskWriter::sha1Sum(long long int offset, long long int length) {
if(r != readData(buf, r, offset)) {
throw string("error");
}
- sha1DigestUpdate(ctx, buf, r);
+ digestUpdate(ctx, buf, r);
}
unsigned char hashValue[20];
- sha1DigestFinal(ctx, hashValue);
+ digestFinal(ctx, hashValue);
return Util::toHex(hashValue, 20);
} catch(string ex) {
throw new DlAbortEx(EX_FILE_SHA1SUM, filename.c_str(), strerror(errno));
diff --git a/src/Base64.cc b/src/Base64.cc
index bcfd7222..71227ac8 100644
--- a/src/Base64.cc
+++ b/src/Base64.cc
@@ -21,62 +21,69 @@
/* copyright --> */
#include "Base64.h"
-string Base64::part_encode(const string& subplain)
-{
- static char base64_table[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', '+', '/',
- };
+static char base64_table[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', '+', '/',
+};
+void Base64::part_encode(const unsigned char* sub, int subLength,
+ unsigned char* buf)
+{
int shift = 2;
- char carry = 0;
- bool ignore_flag = false;
- string crypted;
-
- for(unsigned int index = 0; index < subplain.size(); ++index) {
- if(ignore_flag) {
- crypted += '=';
- } else {
- char cur = subplain.at(index) >> shift | carry;
- if(subplain.at(index) == 0) ignore_flag = true;
- carry = (subplain.at(index) << (6-shift)) & 0x3F;
- shift += 2;
- crypted += base64_table[(unsigned int)cur];
- }
+ unsigned char carry = 0;
+ int index;
+ for(index = 0; index < subLength; index++) {
+ unsigned char cur = sub[index] >> shift | carry;
+ carry = (sub[index] << (6-shift)) & 0x3f;
+ shift += 2;
+ buf[index] = base64_table[(unsigned int)cur];
}
- if(subplain.at(subplain.size()-1) == 0) {
- crypted += '=';
+ if(subLength == 1) {
+ buf[index] = base64_table[(unsigned int)carry];
+ buf[index+1] = buf[index+2] = '=';
+ } else if(subLength == 2) {
+ buf[index] = base64_table[(unsigned int)carry];
+ buf[index+1] = '=';
} else {
- char cur = subplain.at(subplain.size()-1) & 0x3F;
- crypted += base64_table[(unsigned int)cur];
+ unsigned char cur = sub[subLength-1] & 0x3f;
+ buf[index] = base64_table[(unsigned int)cur];
}
-
- return crypted;
}
string Base64::encode(const string& plainSrc)
{
- string plain = plainSrc;
- int remainder = plain.size() % 3;
- if( remainder ) remainder = 3-remainder;
- for(int i = 0; i < remainder; ++i) plain += (char)0;
- string crypted;
- int start_pos = 0;
- for(unsigned int index = 0; plain.size() > index; index += 3) {
- string subplain = plain.substr(start_pos, 3);
- string subcrypted = part_encode(subplain);
- start_pos += 3;
- crypted += subcrypted;
+ unsigned char* result = 0;
+ int resultLength = 0;
+
+ encode((const unsigned char*)plainSrc.c_str(), plainSrc.size(),
+ result, resultLength);
+ string encoded(&result[0], &result[resultLength]);
+ delete [] result;
+ return encoded;
+}
+
+void Base64::encode(const unsigned char* src, int srcLength,
+ unsigned char*& result, int& resultLength) {
+ resultLength = (srcLength+(srcLength%3 == 0 ? 0 : 3-srcLength%3))/3*4;
+ result = new unsigned char[resultLength];
+ unsigned char* tail = result;
+ for(int index = 0; srcLength > index; index += 3) {
+ unsigned char temp[4];
+ part_encode(&src[index],
+ srcLength >= index+3 ? 3 : srcLength-index,
+ temp);
+ memcpy(tail, temp, sizeof(temp));
+ tail += sizeof(temp);
}
- return crypted;
}
+
char Base64::getValue(char ch)
{
char retch;
diff --git a/src/Base64.h b/src/Base64.h
index e40e3b7e..f1ee8262 100644
--- a/src/Base64.h
+++ b/src/Base64.h
@@ -28,12 +28,21 @@ using namespace std;
class Base64
{
private:
+ static void part_encode(const unsigned char* sub, int subLength,
+ unsigned char* buf);
+
static string part_encode(const string& subplain);
static string part_decode(const string& subCrypted);
static char getValue(char ch);
public:
static string encode(const string& plain);
+ // caller must deallocate the memory used by result.
+ static void encode(const unsigned char* src, int srcLength,
+ unsigned char*& result, int& resultLength);
static string decode(const string& crypted);
+ // caller must deallocate the memory used by result.
+ static void decode(const unsigned char* src, int srcLength,
+ unsigned char*& result, int& resultLength);
};
#endif // _BASE64_H_
diff --git a/src/Makefile.am b/src/Makefile.am
index 071d5c3e..cf8fd2b1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -102,12 +102,17 @@ SRCS = Socket.cc Socket.h\
SuggestPieceMessage.cc SuggestPieceMessage.h\
SimplePeerMessage.cc SimplePeerMessage.h\
NullLogger.h\
- Time.cc Time.h
+ Time.cc Time.h\
+ Metalinker.cc Metalinker.h\
+ MetalinkEntry.cc MetalinkEntry.h\
+ MetalinkResource.cc MetalinkResource.h\
+ MetalinkProcessor.h\
+ Xml2MetalinkProcessor.cc Xml2MetalinkProcessor.h
noinst_LIBRARIES = libaria2c.a
libaria2c_a_SOURCES = $(SRCS)
aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
- @LIBGCRYPT_LIBS@ @OPENSSL_LIBS@
+ @LIBGCRYPT_LIBS@ @OPENSSL_LIBS@ @XML_LIBS@
AM_CPPFLAGS = -Wall\
-I../lib -I../intl -I$(top_srcdir)/intl\
- @LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@\
+ @LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@ @XML_CPPFLAGS@\
-D_FILE_OFFSET_BITS=64 -DLOCALEDIR=\"$(localedir)\" @DEFS@ \ No newline at end of file
diff --git a/src/Makefile.in b/src/Makefile.in
index 630fb59d..fd583552 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -109,7 +109,9 @@ am__objects_1 = Socket.$(OBJEXT) SocketCore.$(OBJEXT) \
PortMessage.$(OBJEXT) HaveAllMessage.$(OBJEXT) \
HaveNoneMessage.$(OBJEXT) RejectMessage.$(OBJEXT) \
AllowedFastMessage.$(OBJEXT) SuggestPieceMessage.$(OBJEXT) \
- SimplePeerMessage.$(OBJEXT) Time.$(OBJEXT)
+ SimplePeerMessage.$(OBJEXT) Time.$(OBJEXT) \
+ Metalinker.$(OBJEXT) MetalinkEntry.$(OBJEXT) \
+ MetalinkResource.$(OBJEXT) Xml2MetalinkProcessor.$(OBJEXT)
am_libaria2c_a_OBJECTS = $(am__objects_1)
libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
am__installdirs = "$(DESTDIR)$(bindir)"
@@ -215,6 +217,9 @@ USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
XGETTEXT = @XGETTEXT@
+XML2_CONFIG = @XML2_CONFIG@
+XML_CPPFLAGS = @XML_CPPFLAGS@
+XML_LIBS = @XML_LIBS@
YACC = @YACC@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
@@ -361,16 +366,21 @@ SRCS = Socket.cc Socket.h\
SuggestPieceMessage.cc SuggestPieceMessage.h\
SimplePeerMessage.cc SimplePeerMessage.h\
NullLogger.h\
- Time.cc Time.h
+ Time.cc Time.h\
+ Metalinker.cc Metalinker.h\
+ MetalinkEntry.cc MetalinkEntry.h\
+ MetalinkResource.cc MetalinkResource.h\
+ MetalinkProcessor.h\
+ Xml2MetalinkProcessor.cc Xml2MetalinkProcessor.h
noinst_LIBRARIES = libaria2c.a
libaria2c_a_SOURCES = $(SRCS)
aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
- @LIBGCRYPT_LIBS@ @OPENSSL_LIBS@
+ @LIBGCRYPT_LIBS@ @OPENSSL_LIBS@ @XML_LIBS@
AM_CPPFLAGS = -Wall\
-I../lib -I../intl -I$(top_srcdir)/intl\
- @LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@\
+ @LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@ @XML_CPPFLAGS@\
-D_FILE_OFFSET_BITS=64 -DLOCALEDIR=\"$(localedir)\" @DEFS@
all: all-am
@@ -493,6 +503,9 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/List.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LogFactory.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetaFileUtil.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkEntry.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkResource.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Metalinker.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiDiskAdaptor.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiDiskWriter.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NotInterestedMessage.Po@am__quote@
@@ -535,6 +548,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerWatcherCommand.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnchokeMessage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Util.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2MetalinkProcessor.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
.cc.o:
diff --git a/src/MetalinkEntry.cc b/src/MetalinkEntry.cc
new file mode 100644
index 00000000..506b5999
--- /dev/null
+++ b/src/MetalinkEntry.cc
@@ -0,0 +1,81 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * 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
+ */
+/* copyright --> */
+#include "MetalinkEntry.h"
+#include "Util.h"
+#include <algorithm>
+
+MetalinkEntry::MetalinkEntry() {}
+
+MetalinkEntry::~MetalinkEntry() {
+ for_each(resources.begin(), resources.end(), Deleter());
+}
+
+bool MetalinkEntry::check(const string& filename) const {
+ unsigned char buf[20];
+ int digestLength;
+ const string* digestPtr;
+ MessageDigestContext::HashAlgo algo;
+ if(!sha1.empty()) {
+ digestLength = 20;
+ algo = MessageDigestContext::ALGO_SHA1;
+ digestPtr = &sha1;
+ } else if(!md5.empty()) {
+ digestLength = 16;
+ algo = MessageDigestContext::ALGO_MD5;
+ digestPtr = &md5;
+ } else {
+ return true;
+ }
+ Util::fileChecksum(filename, buf, algo);
+ return *digestPtr == Util::toHex(buf, digestLength);
+}
+
+class PrefOrder {
+public:
+ bool operator()(const MetalinkResource* res1, const MetalinkResource* res2) {
+ return res1->preference > res2->preference;
+ }
+};
+
+void MetalinkEntry::reorderResourcesByPreference() {
+ random_shuffle(resources.begin(), resources.end());
+ sort(resources.begin(), resources.end(), PrefOrder());
+}
+
+class Supported {
+public:
+ bool operator()(const MetalinkResource* res) {
+ switch(res->type) {
+ case MetalinkResource::TYPE_FTP:
+ case MetalinkResource::TYPE_HTTP:
+ return true;
+ default:
+ return false;
+ }
+ }
+};
+
+void MetalinkEntry::dropUnsupportedResource() {
+ MetalinkResources::iterator split =
+ partition(resources.begin(), resources.end(), Supported());
+ resources.erase(split, resources.end());
+}
diff --git a/src/MetalinkEntry.h b/src/MetalinkEntry.h
new file mode 100644
index 00000000..a72158a1
--- /dev/null
+++ b/src/MetalinkEntry.h
@@ -0,0 +1,55 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * 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
+ */
+/* copyright --> */
+#ifndef _D_METALINK_ENTRY_H_
+#define _D_METALINK_ENTRY_H_
+
+#include "common.h"
+#include "MetalinkResource.h"
+#include <deque>
+
+typedef deque<MetalinkResource*> MetalinkResources;
+
+class MetalinkEntry {
+public:
+ string filename;
+ string version;
+ string language;
+ string os;
+ long long int size;
+ string md5;
+ string sha1;
+public:
+ MetalinkResources resources;
+public:
+ MetalinkEntry();
+ ~MetalinkEntry();
+
+ MetalinkEntry& operator=(const MetalinkEntry& metalinkEntry);
+
+ bool check(const string& filename) const;
+
+ void dropUnsupportedResource();
+
+ void reorderResourcesByPreference();
+};
+
+#endif // _D_METALINK_ENTRY_H_
diff --git a/src/MetalinkProcessor.h b/src/MetalinkProcessor.h
new file mode 100644
index 00000000..15eace21
--- /dev/null
+++ b/src/MetalinkProcessor.h
@@ -0,0 +1,35 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * 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
+ */
+/* copyright --> */
+#ifndef _D_METALINK_PROCESSOR_H_
+#define _D_METALINK_PROCESSOR_H_
+
+#include "Metalinker.h"
+#include "common.h"
+
+class MetalinkProcessor {
+public:
+ virtual ~MetalinkProcessor() {}
+
+ virtual Metalinker* parseFile(const string& filename) = 0;
+};
+
+#endif // _D_METALINK_PROCESSOR_H_
diff --git a/src/MetalinkResource.cc b/src/MetalinkResource.cc
new file mode 100644
index 00000000..8b9e7c64
--- /dev/null
+++ b/src/MetalinkResource.cc
@@ -0,0 +1,26 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * 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
+ */
+/* copyright --> */
+#include "MetalinkResource.h"
+
+MetalinkResource::MetalinkResource() {}
+
+MetalinkResource::~MetalinkResource() {}
diff --git a/src/MetalinkResource.h b/src/MetalinkResource.h
new file mode 100644
index 00000000..c3414eb4
--- /dev/null
+++ b/src/MetalinkResource.h
@@ -0,0 +1,47 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * 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
+ */
+/* copyright --> */
+#ifndef _D_METALINK_RESOURCE_H_
+#define _D_METALINK_RESOURCE_H_
+
+#include "common.h"
+
+class MetalinkResource {
+public:
+ enum TYPE {
+ TYPE_FTP,
+ TYPE_HTTP,
+ TYPE_BITTORRENT,
+ TYPE_NOT_SUPPORTED
+ };
+public:
+ string url;
+ int type;
+ string location;
+ int preference;
+public:
+ MetalinkResource();
+ ~MetalinkResource();
+
+ MetalinkResource& operator=(const MetalinkResource& metalinkResource);
+};
+
+#endif // _D_METALINK_RESOURCE_H_
diff --git a/src/Metalinker.cc b/src/Metalinker.cc
new file mode 100644
index 00000000..303ce97b
--- /dev/null
+++ b/src/Metalinker.cc
@@ -0,0 +1,74 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * 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
+ */
+/* copyright --> */
+#include "Metalinker.h"
+#include <algorithm>
+
+Metalinker::Metalinker() {
+}
+
+Metalinker::~Metalinker() {
+ for_each(entries.begin(), entries.end(), Deleter());
+}
+
+class EntryQuery {
+private:
+ string version;
+ string language;
+ string os;
+public:
+ EntryQuery(const string& version,
+ const string& language,
+ const string& os):version(version),
+ language(language),
+ os(os) {}
+ bool operator()(const MetalinkEntry* entry) {
+ if(!version.empty()) {
+ if(version != entry->version) {
+ return false;
+ }
+ }
+ if(!language.empty()) {
+ if(language != entry->language) {
+ return false;
+ }
+ }
+ if(!os.empty()) {
+ if(os != entry->os) {
+ return false;
+ }
+ }
+ return true;
+ }
+};
+
+MetalinkEntry* Metalinker::queryEntry(const string& version,
+ const string& language,
+ const string& os) const {
+ MetalinkEntries::const_iterator itr =
+ find_if(entries.begin(), entries.end(),
+ EntryQuery(version, language, os));
+ if(itr == entries.end()) {
+ return NULL;
+ } else {
+ return *itr;
+ }
+}
diff --git a/src/Metalinker.h b/src/Metalinker.h
new file mode 100644
index 00000000..8eb539d5
--- /dev/null
+++ b/src/Metalinker.h
@@ -0,0 +1,46 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * 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
+ */
+/* copyright --> */
+#ifndef _D_METALINKER_H_
+#define _D_METALINKER_H_
+
+#include "common.h"
+#include "MetalinkEntry.h"
+#include <deque>
+#include <libxml/xpath.h>
+
+typedef deque<MetalinkEntry*> MetalinkEntries;
+
+class Metalinker {
+public:
+ MetalinkEntries entries;
+
+public:
+ Metalinker();
+ ~Metalinker();
+
+ Metalinker& operator=(const Metalinker& metalinker);
+
+ MetalinkEntry* queryEntry(const string& version, const string& language,
+ const string& os) const;
+};
+
+#endif // _D_METALINKER_H_
diff --git a/src/MultiDiskWriter.cc b/src/MultiDiskWriter.cc
index 044796ff..3a67a920 100644
--- a/src/MultiDiskWriter.cc
+++ b/src/MultiDiskWriter.cc
@@ -27,14 +27,15 @@
MultiDiskWriter::MultiDiskWriter(int pieceLength):pieceLength(pieceLength) {
#ifdef ENABLE_SHA1DIGEST
- sha1DigestInit(ctx);
+ ctx.setAlgo(MessageDigestContext::ALGO_SHA1);
+ digestInit(ctx);
#endif // ENABLE_SHA1DIGEST
}
MultiDiskWriter::~MultiDiskWriter() {
clearEntries();
#ifdef ENABLE_SHA1DIGEST
- sha1DigestFree(ctx);
+ digestFree(ctx);
#endif // ENABLE_SHA1DIGEST
}
@@ -150,7 +151,7 @@ void MultiDiskWriter::hashUpdate(DiskWriterEntry* entry, long long int offset, l
if(BUFSIZE != entry->diskWriter->readData(buf, BUFSIZE, offset)) {
throw string("error");
}
- sha1DigestUpdate(ctx, buf, BUFSIZE);
+ digestUpdate(ctx, buf, BUFSIZE);
offset += BUFSIZE;
}
int r = length%BUFSIZE;
@@ -158,7 +159,7 @@ void MultiDiskWriter::hashUpdate(DiskWriterEntry* entry, long long int offset, l
if(r != entry->diskWriter->readData(buf, r, offset)) {
throw string("error");
}
- sha1DigestUpdate(ctx, buf, r);
+ digestUpdate(ctx, buf, r);
}
}
#endif // ENABLE_SHA1DIGEST
@@ -168,7 +169,7 @@ string MultiDiskWriter::sha1Sum(long long int offset, long long int length) {
long long int fileOffset = offset;
bool reading = false;
int rem = length;
- sha1DigestReset(ctx);
+ digestReset(ctx);
try {
for(DiskWriterEntries::iterator itr = diskWriterEntries.begin();
itr != diskWriterEntries.end() && rem != 0; itr++) {
@@ -186,7 +187,7 @@ string MultiDiskWriter::sha1Sum(long long int offset, long long int length) {
throw new DlAbortEx(EX_FILE_OFFSET_OUT_OF_RANGE, offset);
}
unsigned char hashValue[20];
- sha1DigestFinal(ctx, hashValue);
+ digestFinal(ctx, hashValue);
return Util::toHex(hashValue, 20);
} catch(string ex) {
throw new DlAbortEx(EX_FILE_SHA1SUM, "", strerror(errno));
diff --git a/src/PeerConnection.cc b/src/PeerConnection.cc
index b8d3fee9..aa3149e9 100644
--- a/src/PeerConnection.cc
+++ b/src/PeerConnection.cc
@@ -71,8 +71,8 @@ bool PeerConnection::receiveMessage(char* msg, int& length) {
}
//payloadLen = ntohl(nPayloadLen);
int payloadLength = ntohl(*((int*)lenbuf));
- if(payloadLength > MAX_PAYLOAD_LEN) {
- throw new DlAbortEx("max payload length exceeded. length = %d",
+ if(payloadLength > MAX_PAYLOAD_LEN || payloadLength < 0) {
+ throw new DlAbortEx("max payload length exceeded or invalid. length = %d",
payloadLength);
}
currentPayloadLength = payloadLength;
diff --git a/src/PeerMessageUtil.cc b/src/PeerMessageUtil.cc
index 54f9dc98..b13cb401 100644
--- a/src/PeerMessageUtil.cc
+++ b/src/PeerMessageUtil.cc
@@ -57,6 +57,9 @@ void PeerMessageUtil::checkLength(int length) {
throw new DlAbortEx("too large length %d > %dKB", length,
MAX_BLOCK_LENGTH/1024);
}
+ if(length <= 0) {
+ throw new DlAbortEx("invalid length %d", length);
+ }
if(!Util::isPowerOf(length, 2)) {
throw new DlAbortEx("invalid length %d, which is not power of 2",
length);
diff --git a/src/PieceMessage.cc b/src/PieceMessage.cc
index 26ae4e69..073dc364 100644
--- a/src/PieceMessage.cc
+++ b/src/PieceMessage.cc
@@ -81,6 +81,7 @@ void PieceMessage::receivedAction() {
onGotNewPiece(piece);
} else {
onGotWrongPiece(piece);
+ peerInteraction->abortPiece(piece);
}
}
}
diff --git a/src/Request.h b/src/Request.h
index 26ffff1e..dcba6911 100644
--- a/src/Request.h
+++ b/src/Request.h
@@ -103,4 +103,6 @@ public:
};
+typedef deque<Request*> Requests;
+
#endif // _D_REQUEST_H_
diff --git a/src/SegmentMan.h b/src/SegmentMan.h
index aee97cde..53112d6d 100644
--- a/src/SegmentMan.h
+++ b/src/SegmentMan.h
@@ -28,6 +28,7 @@
#include "Option.h"
#include "SegmentSplitter.h"
#include "DiskWriter.h"
+#include "Request.h"
using namespace std;
@@ -92,6 +93,7 @@ public:
const Option* option;
SegmentSplitter* splitter;
DiskWriter* diskWriter;
+ Requests reserved;
SegmentMan();
~SegmentMan();
diff --git a/src/ShaVisitor.cc b/src/ShaVisitor.cc
index b8f8f96f..0781e4dd 100644
--- a/src/ShaVisitor.cc
+++ b/src/ShaVisitor.cc
@@ -24,56 +24,57 @@
ShaVisitor::ShaVisitor() {
#ifdef ENABLE_SHA1DIGEST
- sha1DigestInit(ctx);
- sha1DigestReset(ctx);
+ ctx.setAlgo(MessageDigestContext::ALGO_SHA1);
+ digestInit(ctx);
+ digestReset(ctx);
#endif // ENABLE_SHA1DIGEST
}
ShaVisitor::~ShaVisitor() {
#ifdef ENABLE_SHA1DIGEST
- sha1DigestFree(ctx);
+ digestFree(ctx);
#endif // ENABLE_SHA1DIGEST
}
void ShaVisitor::visit(const Data* d) {
#ifdef ENABLE_SHA1DIGEST
if(d->isNumber()) {
- sha1DigestUpdate(ctx, "i", 1);
+ digestUpdate(ctx, "i", 1);
} else {
string lenStr = Util::llitos(d->getLen());
- sha1DigestUpdate(ctx, lenStr.c_str(), lenStr.size());
- sha1DigestUpdate(ctx, ":", 1);
+ digestUpdate(ctx, lenStr.c_str(), lenStr.size());
+ digestUpdate(ctx, ":", 1);
}
- sha1DigestUpdate(ctx, d->getData(), d->getLen());
+ digestUpdate(ctx, d->getData(), d->getLen());
if(d->isNumber()) {
- sha1DigestUpdate(ctx, "e", 1);
+ digestUpdate(ctx, "e", 1);
}
#endif // ENABLE_SHA1DIGEST
}
void ShaVisitor::visit(const Dictionary* d) {
#ifdef ENABLE_SHA1DIGEST
- sha1DigestUpdate(ctx, "d", 1);
+ digestUpdate(ctx, "d", 1);
const Order& v = d->getOrder();
for(Order::const_iterator itr = v.begin(); itr != v.end(); itr++) {
string lenStr = Util::llitos(itr->size());
- sha1DigestUpdate(ctx, lenStr.c_str(), lenStr.size());
- sha1DigestUpdate(ctx, ":", 1);
- sha1DigestUpdate(ctx, itr->c_str(), itr->size());
+ digestUpdate(ctx, lenStr.c_str(), lenStr.size());
+ digestUpdate(ctx, ":", 1);
+ digestUpdate(ctx, itr->c_str(), itr->size());
const MetaEntry* e = d->get(*itr);
this->visit(e);
}
- sha1DigestUpdate(ctx, "e", 1);
+ digestUpdate(ctx, "e", 1);
#endif // ENABLE_SHA1DIGEST
}
void ShaVisitor::visit(const List* l) {
#ifdef ENABLE_SHA1DIGEST
- sha1DigestUpdate(ctx, "l", 1);
+ digestUpdate(ctx, "l", 1);
for(MetaList::const_iterator itr = l->getList().begin(); itr != l->getList().end(); itr++) {
this->visit(*itr);
}
- sha1DigestUpdate(ctx, "e", 1);
+ digestUpdate(ctx, "e", 1);
#endif // ENABLE_SHA1DIGEST
}
@@ -89,7 +90,7 @@ void ShaVisitor::visit(const MetaEntry* e) {
void ShaVisitor::getHash(unsigned char* hashValue, int& len) {
#ifdef ENABLE_SHA1DIGEST
- sha1DigestFinal(ctx, hashValue);
+ digestFinal(ctx, hashValue);
len = 20;
#endif // ENABLE_SHA1DIGEST
}
diff --git a/src/Util.cc b/src/Util.cc
index c48dfc3d..ffc1e7a9 100644
--- a/src/Util.cc
+++ b/src/Util.cc
@@ -23,9 +23,6 @@
#include "DlAbortEx.h"
#include "File.h"
#include "message.h"
-#ifdef ENABLE_SHA1DIGEST
-#include "messageDigest.h"
-#endif // ENABLE_SHA1DIGEST
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -68,8 +65,8 @@ string Util::llitos(long long int value, bool comma)
}
string Util::trim(const string& src) {
- string::size_type sp = src.find_first_not_of(" ");
- string::size_type ep = src.find_last_not_of(" ");
+ string::size_type sp = src.find_first_not_of("\r\n\t ");
+ string::size_type ep = src.find_last_not_of("\r\n\t ");
if(sp == string::npos || ep == string::npos) {
return "";
} else {
@@ -365,12 +362,47 @@ string Util::getContentDispositionFilename(const string& header) {
void Util::sha1Sum(unsigned char* digest, const void* data, int dataLength) {
#ifdef ENABLE_SHA1DIGEST
- MessageDigestContext ctx;
- sha1DigestInit(ctx);
- sha1DigestReset(ctx);
- sha1DigestUpdate(ctx, data, dataLength);
- sha1DigestFinal(ctx, digest);
- sha1DigestFree(ctx);
+ MessageDigestContext ctx(MessageDigestContext::ALGO_SHA1);
+ digestInit(ctx);
+ digestReset(ctx);
+ digestUpdate(ctx, data, dataLength);
+ digestFinal(ctx, digest);
+ digestFree(ctx);
+#endif // ENABLE_SHA1DIGEST
+}
+
+void Util::fileChecksum(const string& filename, unsigned char* digest,
+ MessageDigestContext::HashAlgo algo) {
+#ifdef ENABLE_SHA1DIGEST
+ MessageDigestContext ctx(algo);
+ digestInit(ctx);
+ digestReset(ctx);
+
+ int BUFLEN = 4096;
+ char buf[BUFLEN];
+
+ int fd;
+ if((fd = open(filename.c_str(), O_RDWR, S_IRUSR|S_IWUSR)) < 0) {
+ throw new DlAbortEx(EX_FILE_OPEN, filename.c_str(), strerror(errno));
+ }
+ while(1) {
+ int size = read(fd, buf, BUFLEN);
+ if(size == -1) {
+ if(errno == EINTR) {
+ continue;
+ } else {
+ close(fd);
+ throw new DlAbortEx(EX_FILE_READ, filename.c_str(), strerror(errno));
+ }
+ } else if(size > 0) {
+ digestUpdate(ctx, buf, size);
+ }
+ if(size < BUFLEN) {
+ break;
+ }
+ }
+ digestFinal(ctx, digest);
+ digestFree(ctx);
#endif // ENABLE_SHA1DIGEST
}
@@ -471,3 +503,29 @@ string Util::randomAlpha(int length) {
}
return str;
}
+
+class UpperCase {
+public:
+ void operator()(char& ch) {
+ ch = toupper(ch);
+ }
+};
+
+string Util::toUpper(const string& src) {
+ string temp = src;
+ for_each(temp.begin(), temp.end(), UpperCase());
+ return temp;
+}
+
+class LowerCase {
+public:
+ void operator()(char& ch) {
+ ch = tolower(ch);
+ }
+};
+
+string Util::toLower(const string& src) {
+ string temp = src;
+ for_each(temp.begin(), temp.end(), LowerCase());
+ return temp;
+}
diff --git a/src/Util.h b/src/Util.h
index 69ad6d1d..75afb8cc 100644
--- a/src/Util.h
+++ b/src/Util.h
@@ -23,6 +23,9 @@
#define _D_UTIL_H_
#include "common.h"
+#ifdef ENABLE_SHA1DIGEST
+#include "messageDigest.h"
+#endif // ENABLE_SHA1DIGEST
#include <string>
#include <utility>
#include <deque>
@@ -82,12 +85,21 @@ public:
// digest must be at least 20 bytes long.
static void sha1Sum(unsigned char* digest, const void* data, int dataLength);
+ // Before call this method, allocate enough memory to the parameter "digest".
+ // For sha1, you need 20 bytes. For md5, 16 bytes.
+ static void fileChecksum(const string& filename, unsigned char* digest,
+ MessageDigestContext::HashAlgo algo);
+
static Integers computeFastSet(string ipaddr, const unsigned char* infoHash,
int pieces, int fastSetSize);
static int countBit(unsigned int);
static string randomAlpha(int length);
+
+ static string toUpper(const string& src);
+
+ static string toLower(const string& src);
};
#endif // _D_UTIL_H_
diff --git a/src/Xml2MetalinkProcessor.cc b/src/Xml2MetalinkProcessor.cc
new file mode 100644
index 00000000..81011803
--- /dev/null
+++ b/src/Xml2MetalinkProcessor.cc
@@ -0,0 +1,188 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * 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
+ */
+/* copyright --> */
+#include "Xml2MetalinkProcessor.h"
+#include "DlAbortEx.h"
+#include "Util.h"
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+Xml2MetalinkProcessor::Xml2MetalinkProcessor():doc(NULL), context(NULL) {}
+
+Xml2MetalinkProcessor::~Xml2MetalinkProcessor() {
+ release();
+}
+
+void Xml2MetalinkProcessor::release() {
+ if(context) {
+ xmlXPathFreeContext(context);
+ context = NULL;
+ }
+ if(doc) {
+ xmlFreeDoc(doc);
+ doc = NULL;
+ }
+}
+
+Metalinker* Xml2MetalinkProcessor::parseFile(const string& filename) {
+ release();
+ doc = xmlParseFile(filename.c_str());
+ if(doc == NULL) {
+ throw new DlAbortEx("Cannot parse metalink file %s", filename.c_str());
+ }
+ context = xmlXPathNewContext(doc);
+ if(context == NULL) {
+ throw new DlAbortEx("Cannot create new xpath context");
+ }
+ string defaultNamespace = "http://www.metalinker.org/";
+ if(xmlXPathRegisterNs(context, (xmlChar*)"m",
+ (xmlChar*)defaultNamespace.c_str()) != 0) {
+ throw new DlAbortEx("Cannot register namespace %s", defaultNamespace.c_str());
+ }
+
+ string xpath = "/m:metalink/m:files/m:file";
+ Metalinker* metalinker = new Metalinker();
+ try {
+ for(int index = 1; 1; index++) {
+ MetalinkEntry* entry = getEntry(xpath+"["+Util::itos(index)+"]");
+ if(entry == NULL) {
+ break;
+ } else {
+ metalinker->entries.push_back(entry);
+ }
+ }
+ } catch(Exception* e) {
+ delete metalinker;
+ throw;
+ }
+ return metalinker;
+}
+
+MetalinkEntry* Xml2MetalinkProcessor::getEntry(const string& xpath) {
+ xmlXPathObjectPtr result = xpathEvaluation(xpath);
+ if(result == NULL) {
+ return NULL;
+ }
+ xmlXPathFreeObject(result);
+ MetalinkEntry* entry = new MetalinkEntry();
+ try {
+ entry->version = Util::trim(xpathContent(xpath+"/m:version"));
+ entry->language = Util::trim(xpathContent(xpath+"/m:language"));
+ entry->os = Util::trim(xpathContent(xpath+"/m:os"));
+ entry->md5 = Util::trim(xpathContent(xpath+"/m:verification/m:hash[@type=\"md5\"]"));
+ entry->sha1 = Util::trim(xpathContent(xpath+"/m:verification/m:hash[@type=\"sha1\"]"));
+ for(int index = 1; 1; index++) {
+ MetalinkResource* resource =
+ getResource(xpath+"/m:resources/m:url["+Util::itos(index)+"]");
+ if(resource == NULL) {
+ break;
+ } else {
+ entry->resources.push_back(resource);
+ }
+ }
+ } catch(Exception* e) {
+ delete entry;
+ throw;
+ }
+
+ return entry;
+}
+
+MetalinkResource* Xml2MetalinkProcessor::getResource(const string& xpath) {
+ xmlXPathObjectPtr result = xpathEvaluation(xpath);
+ if(result == NULL) {
+ return NULL;
+ }
+ MetalinkResource* resource = new MetalinkResource();
+ try {
+ xmlNodeSetPtr nodeSet = result->nodesetval;
+ xmlNodePtr node = nodeSet->nodeTab[0];
+ string type = Util::trim(xmlAttribute(node, "type"));
+ if(type == "ftp") {
+ resource->type = MetalinkResource::TYPE_FTP;
+ } else if(type == "http") {
+ resource->type = MetalinkResource::TYPE_HTTP;
+ } else if(type == "bittorrent") {
+ resource->type = MetalinkResource::TYPE_BITTORRENT;
+ } else {
+ resource->type = MetalinkResource::TYPE_NOT_SUPPORTED;
+ }
+ string pref = Util::trim(xmlAttribute(node, "preference"));
+ if(pref.empty()) {
+ resource->preference = 100;
+ } else {
+ resource->preference = STRTOLL(pref.c_str());
+ }
+ resource->url = Util::trim(xmlContent(node));
+ } catch(Exception* e) {
+ delete resource;
+ throw e;
+ }
+ return resource;
+}
+
+xmlXPathObjectPtr Xml2MetalinkProcessor::xpathEvaluation(const string& xpath) {
+ xmlXPathObjectPtr result = xmlXPathEvalExpression((xmlChar*)xpath.c_str(),
+ context);
+ if(result == NULL) {
+ throw new DlAbortEx("Cannot evaluate xpath %s", xpath.c_str());
+ }
+ if(xmlXPathNodeSetIsEmpty(result->nodesetval)) {
+ xmlXPathFreeObject(result);
+ return NULL;
+ }
+ return result;
+}
+
+string Xml2MetalinkProcessor::xmlAttribute(xmlNodePtr node, const string& attrName) {
+ xmlChar* temp = xmlGetNoNsProp(node, (xmlChar*)attrName.c_str());
+ if(temp == NULL) {
+ return "";
+ } else {
+ string attr = (char*)temp;
+ xmlFree(temp);
+ return attr;
+ }
+}
+
+string Xml2MetalinkProcessor::xmlContent(xmlNodePtr node) {
+ xmlChar* temp = xmlNodeGetContent(node);
+ if(temp == NULL) {
+ return "";
+ } else {
+ string content = (char*)temp;
+ xmlFree(temp);
+ return content;
+ }
+}
+
+string Xml2MetalinkProcessor::xpathContent(const string& xpath) {
+ xmlXPathObjectPtr result = xpathEvaluation(xpath);
+ if(result == NULL) {
+ return "";
+ }
+ xmlNodeSetPtr nodeSet = result->nodesetval;
+ xmlNodePtr node = nodeSet->nodeTab[0]->children;
+ string content = (char*)node->content;
+ xmlXPathFreeObject(result);
+ return content;
+}
diff --git a/src/Xml2MetalinkProcessor.h b/src/Xml2MetalinkProcessor.h
new file mode 100644
index 00000000..65358a6f
--- /dev/null
+++ b/src/Xml2MetalinkProcessor.h
@@ -0,0 +1,51 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * 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
+ */
+/* copyright --> */
+#ifndef _D_XML2_METALINK_PROCESSOR_H_
+#define _D_XML2_METALINK_PROCESSOR_H_
+
+#include "MetalinkProcessor.h"
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+class Xml2MetalinkProcessor : public MetalinkProcessor {
+private:
+ xmlDocPtr doc;
+ xmlXPathContextPtr context;
+
+ MetalinkEntry* getEntry(const string& xpath);
+ MetalinkResource* getResource(const string& xpath);
+
+ xmlXPathObjectPtr xpathEvaluation(const string& xpath);
+ string xpathContent(const string& xpath);
+ string xmlAttribute(xmlNodePtr node, const string& attrName);
+ string xmlContent(xmlNodePtr node);
+
+ void release();
+public:
+ Xml2MetalinkProcessor();
+ virtual ~Xml2MetalinkProcessor();
+
+ virtual Metalinker* parseFile(const string& filename);
+
+};
+
+#endif // _D_XML2_METALINK_PROCESSOR_H_
diff --git a/src/main.cc b/src/main.cc
index 59f77978..51dfd800 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -37,6 +37,7 @@
#include "TrackerUpdateCommand.h"
#include "ByteArrayDiskWriter.h"
#include "PeerChokeCommand.h"
+#include "Xml2MetalinkProcessor.h"
#include <deque>
#include <algorithm>
#include <time.h>
@@ -59,7 +60,10 @@ extern int optind, opterr, optopt;
using namespace std;
-typedef deque<Request*> Requests;
+bool readyToTorrentMode = false;
+string downloadedTorrentFile;
+bool readyToMetalinkMode = false;
+string downloadedMetalinkFile;
void printDownloadCompeleteMessage(string filename) {
printf(_("\nThe download was complete. <%s>\n"), filename.c_str());
@@ -115,11 +119,10 @@ void torrentHandler(int signal) {
te->torrentMan->setHalt(true);
}
-void addCommand(int cuid, const string& url, string referer, Requests& requests) {
+void createRequest(int cuid, const string& url, string referer, Requests& requests) {
Request* req = new Request();
req->setReferer(referer);
if(req->setUrl(url)) {
- e->commands.push_back(InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, req, e));
requests.push_back(req);
} else {
fprintf(stderr, _("Unrecognized URL or unsupported protocol: %s\n"), req->getUrl().c_str());
@@ -258,6 +261,54 @@ void showUsage() {
cout << endl;
}
+bool normalDownload(const Requests& requests,
+ const Requests& reserved,
+ Option* op,
+ const string& dir,
+ const string& ufilename,
+ string& downloadedFilename) {
+ setSignalHander(SIGINT, handler, 0);
+ setSignalHander(SIGTERM, handler, 0);
+
+ e = new ConsoleDownloadEngine();
+ e->option = op;
+ e->segmentMan = new SegmentMan();
+ e->segmentMan->diskWriter = new DefaultDiskWriter();
+ e->segmentMan->dir = dir;
+ e->segmentMan->ufilename = ufilename;
+ e->segmentMan->option = op;
+ e->segmentMan->splitter = new SplitSlowestSegmentSplitter();
+ e->segmentMan->splitter->setMinSegmentSize(op->getAsLLInt(PREF_MIN_SEGMENT_SIZE));
+ e->segmentMan->reserved = reserved;
+
+ int cuidCounter = 1;
+ for(Requests::const_iterator itr = requests.begin();
+ itr != requests.end();
+ itr++, cuidCounter++) {
+ e->commands.push_back(InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuidCounter, *itr, e));
+ }
+ e->run();
+ bool success = false;
+ if(e->segmentMan->finished()) {
+ printDownloadCompeleteMessage(e->segmentMan->getFilePath());
+ if(Util::endsWith(e->segmentMan->getFilePath(), ".torrent")) {
+ downloadedTorrentFile = e->segmentMan->getFilePath();
+ readyToTorrentMode = true;
+ } else if(Util::endsWith(e->segmentMan->getFilePath(), ".metalink")) {
+ downloadedMetalinkFile = e->segmentMan->getFilePath();
+ readyToMetalinkMode = true;
+ }
+ downloadedFilename = e->segmentMan->getFilePath();
+ success = true;
+ } else {
+ printDownloadAbortMessage();
+ }
+ e->cleanQueue();
+ delete e;
+
+ return success;
+}
+
int main(int argc, char* argv[]) {
#ifdef ENABLE_NLS
setlocale (LC_CTYPE, "");
@@ -273,13 +324,23 @@ int main(int argc, char* argv[]) {
bool daemonMode = false;
string referer;
string torrentFile;
+ string metalinkFile;
int listenPort = -1;
+ string metalinkVersion;
+ string metalinkLanguage;
+ string metalinkOs;
+ int metalinkConnection = 15;
Integers selectFileIndexes;
#ifdef ENABLE_BITTORRENT
bool followTorrent = true;
#else
bool followTorrent = false;
#endif // ENABLE_BITTORRENT
+#ifdef ENABLE_METALINK
+ bool followMetalink = true;
+#else
+ bool followMetalink = false;
+#endif // ENABLE_METALINK
int c;
Option* op = new Option();
@@ -333,11 +394,15 @@ int main(int argc, char* argv[]) {
{ "upload-limit", required_argument, &lopt, 20 },
{ "select-file", required_argument, &lopt, 21 },
#endif // ENABLE_BITTORRENT
+#ifdef ENABLE_METALINK
+ { "metalink-file", required_argument, NULL, 'M' },
+ { "metalink-connection", required_argument, NULL, 'C' },
+#endif // ENABLE_METALINK
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, 0, 0 }
};
- c = getopt_long(argc, argv, "Dd:o:l:s:pt:m:vhST:", longOpts, &optIndex);
+ c = getopt_long(argc, argv, "Dd:o:l:s:pt:m:vhST:M:C:", longOpts, &optIndex);
if(c == -1) {
break;
}
@@ -549,6 +614,17 @@ int main(int argc, char* argv[]) {
case 'T':
torrentFile = string(optarg);
break;
+ case 'M':
+ metalinkFile = string(optarg);
+ break;
+ case 'C':
+ metalinkConnection = (int)strtol(optarg, NULL, 10);
+ if(metalinkConnection <= 0) {
+ cerr << _("metalink-connection must be greater than 0.") << endl;
+ showUsage();
+ exit(1);
+ }
+ break;
case 'v':
showVersion();
exit(0);
@@ -560,7 +636,7 @@ int main(int argc, char* argv[]) {
exit(1);
}
}
- if(torrentFile.empty()) {
+ if(torrentFile.empty() && metalinkFile.empty()) {
if(optind == argc) {
cerr << _("specify at least one URL") << endl;
showUsage();
@@ -584,6 +660,9 @@ int main(int argc, char* argv[]) {
#ifdef HAVE_LIBGNUTLS
gnutls_global_init();
#endif // HAVE_LIBGNUTLS
+#ifdef HAVE_LIBXML2
+ xmlInitParser();
+#endif // HAVE_LIBXML2
srandom(time(NULL));
if(stdoutLog) {
LogFactory::setLogFile("/dev/stdout");
@@ -601,50 +680,76 @@ int main(int argc, char* argv[]) {
setSignalHander(SIGPIPE, SIG_IGN, 0);
- bool readyToTorrentMode = false;
- string downloadedTorrentFile;
- if(torrentFile.empty()) {
- setSignalHander(SIGINT, handler, 0);
- setSignalHander(SIGTERM, handler, 0);
-
- e = new ConsoleDownloadEngine();
- e->option = op;
- e->segmentMan = new SegmentMan();
- e->segmentMan->diskWriter = new DefaultDiskWriter();
- e->segmentMan->dir = dir;
- e->segmentMan->ufilename = ufilename;
- e->segmentMan->option = op;
- e->segmentMan->splitter = new SplitSlowestSegmentSplitter();
- e->segmentMan->splitter->setMinSegmentSize(op->getAsLLInt(PREF_MIN_SEGMENT_SIZE));
-
-
+ if(torrentFile.empty() && metalinkFile.empty()) {
Requests requests;
int cuidCounter = 1;
for(Strings::const_iterator itr = args.begin(); itr != args.end(); itr++) {
for(int s = 1; s <= split; s++) {
- addCommand(cuidCounter, *itr, referer, requests);
+ createRequest(cuidCounter, *itr, referer, requests);
cuidCounter++;
}
}
+ setSignalHander(SIGINT, handler, 0);
+ setSignalHander(SIGTERM, handler, 0);
+
+ Requests reserved;
+ string downloadedFilename;
+ normalDownload(requests, reserved, op, dir, ufilename, downloadedFilename);
- e->run();
+ for_each(requests.begin(), requests.end(), Deleter());
+ requests.clear();
+ }
+ if(!metalinkFile.empty() || followMetalink && readyToMetalinkMode) {
+ string targetMetalinkFile = metalinkFile.empty() ?
+ downloadedMetalinkFile : metalinkFile;
+ Xml2MetalinkProcessor proc;
+ Metalinker* metalinker = proc.parseFile(targetMetalinkFile);
- if(e->segmentMan->finished()) {
- printDownloadCompeleteMessage(e->segmentMan->getFilePath());
- if(Util::endsWith(e->segmentMan->getFilePath(), ".torrent")) {
- downloadedTorrentFile = e->segmentMan->getFilePath();
- readyToTorrentMode = true;
- }
- } else {
- printDownloadAbortMessage();
+ MetalinkEntry* entry = metalinker->queryEntry(metalinkVersion,
+ metalinkLanguage,
+ metalinkOs);
+ if(entry == NULL) {
+ printf("No file matched with your preference");
+ exit(1);
+ }
+ entry->dropUnsupportedResource();
+ entry->reorderResourcesByPreference();
+ Requests requests;
+ int cuidCounter = 1;
+ for(MetalinkResources::const_iterator itr = entry->resources.begin();
+ itr != entry->resources.end(); itr++) {
+ MetalinkResource* resource = *itr;
+ createRequest(cuidCounter, resource->url, referer, requests);
+ cuidCounter++;
+ }
+ Requests reserved;
+ if((int)requests.size() > metalinkConnection) {
+ copy(requests.begin()+metalinkConnection, requests.end(),
+ insert_iterator<Requests>(reserved, reserved.end()));
+ requests.erase(requests.begin()+metalinkConnection, requests.end());
}
+
+ setSignalHander(SIGINT, handler, 0);
+ setSignalHander(SIGTERM, handler, 0);
+
+ string downloadedFilename;
+ bool success = normalDownload(requests, reserved, op, dir, ufilename,
+ downloadedFilename);
+
for_each(requests.begin(), requests.end(), Deleter());
requests.clear();
- e->cleanQueue();
- delete e;
- }
- if(!torrentFile.empty() || followTorrent && readyToTorrentMode) {
+ if(success) {
+ if(entry->check(downloadedFilename)) {
+ printf("checksum OK.\n");
+ } else {
+ printf("checksum ERROR.\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ delete metalinker;
+ } else if(!torrentFile.empty() || followTorrent && readyToTorrentMode) {
try {
//op->put(PREF_MAX_TRIES, "0");
setSignalHander(SIGINT, torrentHandler, SA_RESETHAND);
@@ -735,5 +840,8 @@ int main(int argc, char* argv[]) {
#ifdef HAVE_LIBGNUTLS
gnutls_global_deinit();
#endif // HAVE_LIBGNUTLS
+#ifdef HAVE_LIBXML2
+ xmlCleanupParser();
+#endif // HAVE_LIBXML2
return 0;
}
diff --git a/src/messageDigest.h b/src/messageDigest.h
index a5f6c268..a514441c 100644
--- a/src/messageDigest.h
+++ b/src/messageDigest.h
@@ -28,30 +28,79 @@
#ifdef HAVE_LIBSSL
#include <openssl/evp.h>
-#define MessageDigestContext EVP_MD_CTX
-#define sha1DigestInit(CTX) EVP_MD_CTX_init(&CTX)
-#define sha1DigestReset(CTX) EVP_DigestInit_ex(&CTX, EVP_sha1(), NULL)
-#define sha1DigestUpdate(CTX, DATA, LENGTH) EVP_DigestUpdate(&CTX, DATA, LENGTH)
-#define sha1DigestFinal(CTX, HASH) \
+#endif // HAVE_LIBSSL
+
+#ifdef HAVE_LIBGCRYPT
+#include <gcrypt.h>
+#endif // HAVE_LIBGCRYPT
+
+class MessageDigestContext {
+public:
+ enum HashAlgo {
+ ALGO_MD5,
+ ALGO_SHA1
+ };
+#ifdef HAVE_LIBSSL
+ EVP_MD_CTX ctx;
+ const EVP_MD* algo;
+#endif // HAVE_LIBSSL
+#ifdef HAVE_LIBGCRYPT
+ gcry_md_hd_t ctx;
+ int algo;
+#endif // HAVE_LIBGCRYPT
+
+ MessageDigestContext() {}
+ MessageDigestContext(HashAlgo algo) {
+ setAlgo(algo);
+ }
+
+ void setAlgo(HashAlgo algo) {
+ switch(algo) {
+ case ALGO_MD5:
+#ifdef HAVE_LIBSSL
+ this->algo = EVP_md5();
+#endif // HAVE_LIBSSL
+#ifdef HAVE_LIBGCRYPT
+ this->algo = GCRY_MD_MD5;
+#endif // HAVE_LIBGCRYPT
+ break;
+ case ALGO_SHA1:
+#ifdef HAVE_LIBSSL
+ this->algo = EVP_sha1();
+#endif // HAVE_LIBSSL
+#ifdef HAVE_LIBGCRYPT
+ this->algo = GCRY_MD_SHA1;
+#endif // HAVE_LIBGCRYPT
+ break;
+ default:
+ break;
+ }
+ }
+};
+
+#ifdef HAVE_LIBSSL
+#define digestInit(CTX) EVP_MD_CTX_init(&CTX.ctx)
+#define digestReset(CTX) EVP_DigestInit_ex(&CTX.ctx, CTX.algo, NULL)
+#define digestUpdate(CTX, DATA, LENGTH) EVP_DigestUpdate(&CTX.ctx, DATA, LENGTH)
+#define digestFinal(CTX, HASH) \
{\
int len;\
-EVP_DigestFinal_ex(&CTX, HASH, (unsigned int*)&len);\
+EVP_DigestFinal_ex(&CTX.ctx, HASH, (unsigned int*)&len);\
}
-#define sha1DigestFree(CTX) EVP_MD_CTX_cleanup(&CTX)
+#define digestFree(CTX) EVP_MD_CTX_cleanup(&CTX.ctx)
+
#endif // HAVE_LIBSSL
#ifdef HAVE_LIBGCRYPT
-#include <gcrypt.h>
-#define MessageDigestContext gcry_md_hd_t
-#define sha1DigestInit(CTX) gcry_md_open(&CTX, GCRY_MD_SHA1, 0)
-#define sha1DigestReset(CTX) gcry_md_reset(CTX)
-#define sha1DigestUpdate(CTX, DATA, LENGTH) gcry_md_write(CTX, DATA, LENGTH)
-#define sha1DigestFinal(CTX, HASH) \
+#define digestInit(CTX) gcry_md_open(&CTX.ctx, CTX.algo, 0)
+#define digestReset(CTX) gcry_md_reset(CTX.ctx)
+#define digestUpdate(CTX, DATA, LENGTH) gcry_md_write(CTX.ctx, DATA, LENGTH)
+#define digestFinal(CTX, HASH) \
{\
-gcry_md_final(CTX);\
-memcpy(HASH, gcry_md_read(CTX, 0), 20);\
+gcry_md_final(CTX.ctx);\
+memcpy(HASH, gcry_md_read(CTX.ctx, 0), gcry_md_get_algo_dlen(CTX.algo));\
}
-#define sha1DigestFree(CTX) gcry_md_close(CTX)
+#define digestFree(CTX) gcry_md_close(CTX.ctx)
#endif // HAVE_LIBGCRYPT
#endif // ENABLE_BITTORRENT
diff --git a/test/Base64Test.cc b/test/Base64Test.cc
index 9ace6f5b..e7497312 100644
--- a/test/Base64Test.cc
+++ b/test/Base64Test.cc
@@ -26,6 +26,14 @@ CPPUNIT_TEST_SUITE_REGISTRATION( Base64Test );
void Base64Test::testEncode() {
CPPUNIT_ASSERT_EQUAL(string("SGVsbG8gV29ybGQh"),
Base64::encode("Hello World!"));
+ CPPUNIT_ASSERT_EQUAL(string("SGVsbG8gV29ybGQ="),
+ Base64::encode("Hello World"));
+ CPPUNIT_ASSERT_EQUAL(string("SGVsbG8gV29ybA=="),
+ Base64::encode("Hello Worl"));
+ CPPUNIT_ASSERT_EQUAL(string("YQ=="),
+ Base64::encode("a"));
+ CPPUNIT_ASSERT_EQUAL(string(""),
+ Base64::encode(""));
}
void Base64Test::testDecode() {
diff --git a/test/Makefile.am b/test/Makefile.am
index 215c8903..e8fc2ca8 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -31,16 +31,19 @@ aria2c_SOURCES = AllTest.cc\
PieceMessageTest.cc\
RejectMessageTest.cc\
AllowedFastMessageTest.cc\
- SuggestPieceMessageTest.cc
+ SuggestPieceMessageTest.cc\
+ Xml2MetalinkProcessorTest.cc\
+ MetalinkerTest.cc\
+ MetalinkEntryTest.cc
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
#aria2c_LDFLAGS = ${CPPUNIT_LIBS}
aria2c_LDADD = ../src/libaria2c.a\
${CPPUNIT_LIBS} @LIBGNUTLS_LIBS@\
- @LIBGCRYPT_LIBS@ @OPENSSL_LIBS@
+ @LIBGCRYPT_LIBS@ @OPENSSL_LIBS@ @XML_LIBS@
AM_CPPFLAGS = -Wall\
${CPPUNIT_CFLAGS}\
-I ../src\
-I../lib -I../intl -I$(top_srcdir)/intl\
- @LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@\
+ @LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@ @XML_CPPFLAGS@\
-D_FILE_OFFSET_BITS=64 -DLOCALEDIR=\"$(localedir)\" @DEFS@
diff --git a/test/Makefile.in b/test/Makefile.in
index 2490ea5e..0c1606b2 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -71,7 +71,9 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) RequestTest.$(OBJEXT) \
BitfieldMessageTest.$(OBJEXT) RequestMessageTest.$(OBJEXT) \
CancelMessageTest.$(OBJEXT) PieceMessageTest.$(OBJEXT) \
RejectMessageTest.$(OBJEXT) AllowedFastMessageTest.$(OBJEXT) \
- SuggestPieceMessageTest.$(OBJEXT)
+ SuggestPieceMessageTest.$(OBJEXT) \
+ Xml2MetalinkProcessorTest.$(OBJEXT) MetalinkerTest.$(OBJEXT) \
+ MetalinkEntryTest.$(OBJEXT)
aria2c_OBJECTS = $(am_aria2c_OBJECTS)
am__DEPENDENCIES_1 =
aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1)
@@ -168,6 +170,9 @@ USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
XGETTEXT = @XGETTEXT@
+XML2_CONFIG = @XML2_CONFIG@
+XML_CPPFLAGS = @XML_CPPFLAGS@
+XML_LIBS = @XML_LIBS@
YACC = @YACC@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
@@ -243,19 +248,22 @@ aria2c_SOURCES = AllTest.cc\
PieceMessageTest.cc\
RejectMessageTest.cc\
AllowedFastMessageTest.cc\
- SuggestPieceMessageTest.cc
+ SuggestPieceMessageTest.cc\
+ Xml2MetalinkProcessorTest.cc\
+ MetalinkerTest.cc\
+ MetalinkEntryTest.cc
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
#aria2c_LDFLAGS = ${CPPUNIT_LIBS}
aria2c_LDADD = ../src/libaria2c.a\
${CPPUNIT_LIBS} @LIBGNUTLS_LIBS@\
- @LIBGCRYPT_LIBS@ @OPENSSL_LIBS@
+ @LIBGCRYPT_LIBS@ @OPENSSL_LIBS@ @XML_LIBS@
AM_CPPFLAGS = -Wall\
${CPPUNIT_CFLAGS}\
-I ../src\
-I../lib -I../intl -I$(top_srcdir)/intl\
- @LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@\
+ @LIBGNUTLS_CFLAGS@ @LIBGCRYPT_CFLAGS@ @OPENSSL_CFLAGS@ @XML_CPPFLAGS@\
-D_FILE_OFFSET_BITS=64 -DLOCALEDIR=\"$(localedir)\" @DEFS@
all: all-am
@@ -323,6 +331,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InterestedMessageTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ListTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetaFileUtilTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkEntryTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkerTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiDiskWriterTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NotInterestedMessageTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OptionTest.Po@am__quote@
@@ -336,6 +346,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentManTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnchokeMessageTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2MetalinkProcessorTest.Po@am__quote@
.cc.o:
@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
diff --git a/test/UtilTest.cc b/test/UtilTest.cc
index 2081d0a7..150c8f68 100644
--- a/test/UtilTest.cc
+++ b/test/UtilTest.cc
@@ -17,6 +17,9 @@ class UtilTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testGetContentDispositionFilename);
CPPUNIT_TEST(testComputeFastSet);
CPPUNIT_TEST(testRandomAlpha);
+ CPPUNIT_TEST(testFileChecksum);
+ CPPUNIT_TEST(testToUpper);
+ CPPUNIT_TEST(testToLower);
CPPUNIT_TEST_SUITE_END();
private:
@@ -34,6 +37,9 @@ public:
// may be moved to other helper class in the future.
void testGetContentDispositionFilename();
void testRandomAlpha();
+ void testFileChecksum();
+ void testToUpper();
+ void testToLower();
};
@@ -214,3 +220,31 @@ void UtilTest::testComputeFastSet() {
void UtilTest::testRandomAlpha() {
CPPUNIT_ASSERT_EQUAL(string("rUopvKRn"), Util::randomAlpha(8));
}
+
+void UtilTest::testFileChecksum() {
+ unsigned char buf[20];
+ string filename = "4096chunk.txt";
+ Util::fileChecksum(filename, buf, MessageDigestContext::ALGO_SHA1);
+ string sha1 = Util::toHex(buf, 20);
+ CPPUNIT_ASSERT_EQUAL(string("608cabc0f2fa18c260cafd974516865c772363d5"),
+ sha1);
+
+ Util::fileChecksum(filename, buf, MessageDigestContext::ALGO_MD5);
+ string md5 = Util::toHex(buf, 16);
+ CPPUNIT_ASSERT_EQUAL(string("82a7348c2e03731109d0cf45a7325b88"),
+ md5);
+}
+
+void UtilTest::testToUpper() {
+ string src = "608cabc0f2fa18c260cafd974516865c772363d5";
+ string upp = "608CABC0F2FA18C260CAFD974516865C772363D5";
+
+ CPPUNIT_ASSERT_EQUAL(upp, Util::toUpper(src));
+}
+
+void UtilTest::testToLower() {
+ string src = "608CABC0F2FA18C260CAFD974516865C772363D5";
+ string upp = "608cabc0f2fa18c260cafd974516865c772363d5";
+
+ CPPUNIT_ASSERT_EQUAL(upp, Util::toLower(src));
+}