diff --git a/AUTHORS b/AUTHORS index f6cc2425..9b3156e1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -16,13 +16,17 @@ ITriskTI Igor Khomyakov Jarda Snajdr Kcchouette +Kurt Kartaltepe +Mingye Wang Nils Maier ORiON- +ReadmeCritic Ross Smith II Ryan Steinmetz Ryo ONODERA Sarim Khan Sergey Zolotarev +Sonny Piers Tatsuhiro Tsujikawa Vasilij Schneidermann Zoltan Toth-Czifra @@ -36,6 +40,6 @@ luokar mozillazg multisnow oliviercommelarbre -Sonny Piers +rotor [1] https://gist.github.com/tatsuhiro-t/deaffeb064652104ad11 diff --git a/NEWS b/NEWS index 879c6d16..9f546d8d 100644 --- a/NEWS +++ b/NEWS @@ -1,37 +1,79 @@ -aria2 1.22.0 +aria2 1.23.0 ============ Release Note ------------ -This release adds new feature that manages the number of concurrent -downloads dynamically. --stream-piece-selector option gets new value -"random" which randomizes the piece selection for HTTP/FTP downloads. -This effectively randomizes the order of files on multi-file Web -Seeding. Now all contributor's names are in AUTHORS file. -Previously, aria2 shows error when it sees floating point number in a -torrent file because torrent file specification does not allow -floating point number. In this release, they are just ignored, and -aria2 continues to parse the rest of the torrent file as if there is -nothing wrong. +This release fixes several bugs reported by users, and adds several +new features. Read the following section for details. Changes ------- -* Add description about possible fragmentation with - --file-allocation=trunc +* Simplify cache write -* Make single-entry metalink download with multi-file torrent work + The previous cache write routine was too complex. I'm sure I can + rewrite it to more elegantly. But the primary motivation of this + complex logic is for disk activity reduction on Windows 7, and I + observed it on my old IDE disk. I checked it again recently, and + there is no difference between with and without this complex logic. + For this reason, it was removed. Will revert this change if many of + users are not happy with this. -* Add all contributor's names in AUTHORS +* Allow subsecond value in ns cookie.txt file's expiry time field -* Ignore floating number in torrent file + Fixes GH-655 -* Added support for a dynamic management of the number of concurrent - downloads as a function of the overall bandwidth observed +* Adjust chromium cookie time - This change adds --optimize-concurrent-downloads option. +* import-po: iterate on glob, not ls output - Patch from oliviercommelarbre + Patch from Mingye Wang -* Add --stream-piece-selector=random +* Add --stderr option to redirect all stdout log output to stderr + + Fixes GH-638 + +* Add "hide" to --download-result option + + Fixes GH-639 + +* Fix downloaded metaurl torrent filename + +* Add a little bit of color to have a better visual of important + informations + + Patch from rotor + +* Update README URLs based on HTTP redirects + + Patch from ReadmeCritic + +* Relocate from github.com/tatsuhiro-t/aria2 to github.com/aria2/aria2 + + Fixes GH-602 + +* mingw: Defer the falloc warning until falloc is specified by option + + Fixes GH-594 + +* Add bittorrent key to aria2.tellStopped status + + Fixes GH-612 + +* Addsystem.listNotifications RPC method + + Merges GH-620 + + Patch from Sonny Piers + +* Report CheckIntegrity info in tellStatus + + - Adds verifiedLength to tellStatus. Reports the length of data that + has been verified of the current RequestGroup being verified. + - Adds verifyPending to tellStatus. Reports if the RequestGroup has + a verification of integrity pending. + + Closes GH-561 + + Patch from Kurt Kartaltepe diff --git a/README.android b/README.android index 017750e5..3626aa5e 100644 --- a/README.android +++ b/README.android @@ -42,7 +42,7 @@ aria2c executable was generated using android-ndk-r10d. The following libraries were statically linked. -* openssl 1.0.2g +* openssl 1.0.2h * expat 2.1.0 * c-ares 1.11.0 * libssh2 1.7.0 diff --git a/configure.ac b/configure.ac index fe1164cc..ae7b6f8f 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. # AC_PREREQ([2.67]) -AC_INIT([aria2],[1.22.0],[https://github.com/aria2/aria2/issues],[aria2],[https://aria2.github.io/]) +AC_INIT([aria2],[1.23.0],[https://github.com/aria2/aria2/issues],[aria2],[https://aria2.github.io/]) AC_CANONICAL_HOST AC_CANONICAL_TARGET diff --git a/doc/bash_completion/aria2c b/doc/bash_completion/aria2c index 9ba44bd1..407beaf1 100644 --- a/doc/bash_completion/aria2c +++ b/doc/bash_completion/aria2c @@ -52,7 +52,7 @@ _aria2c() return 0 ;; --download-result) - COMPREPLY=( $( compgen -W 'default full' -- "$cur" ) ) + COMPREPLY=( $( compgen -W 'default full hide' -- "$cur" ) ) return 0 ;; --dir) @@ -70,7 +70,7 @@ _aria2c() esac case $cur in -*) - COMPREPLY=( $( compgen -W '--rpc-save-upload-metadata --rpc-save-upload-metadata=false --on-download-start --metalink-language --rpc-secret --torrent-file --enable-peer-exchange --enable-peer-exchange=false --http-proxy-passwd --bt-tracker-timeout --ftp-type --seed-time --bt-tracker-connect-timeout --bt-max-open-files --no-netrc --no-netrc=false --force-sequential --force-sequential=false --metalink-base-uri --private-key --ftp-passwd --allow-overwrite --allow-overwrite=false --rpc-allow-origin-all --rpc-allow-origin-all=false --bt-detach-seed-only --bt-detach-seed-only=false --dht-entry-point6 --summary-interval --lowest-speed-limit --bt-tracker-interval --proxy-method --metalink-preferred-protocol --enable-http-keep-alive --enable-http-keep-alive=false --metalink-version --bt-lpd-interface --force-save --force-save=false --rpc-secure --rpc-secure=false --listen-port --rpc-private-key --server-stat-of --server-stat-timeout --https-proxy-user --piece-length --dry-run --dry-run=false --truncate-console-readout --truncate-console-readout=false --async-dns-server --bt-max-peers --max-overall-upload-limit --rpc-user --optimize-concurrent-downloads --optimize-concurrent-downloads=true --optimize-concurrent-downloads=false --optimize-concurrent-downloads=A:B --dir --split --on-download-pause --auto-file-renaming --auto-file-renaming=false --http-proxy --save-session-interval --daemon --daemon=false --https-proxy --min-tls-version --save-cookies --out --rlimit-nofile --max-file-not-found --on-download-stop --certificate --bt-min-crypto-level --remove-control-file --remove-control-file=false --enable-dht --enable-dht=false --file-allocation --follow-metalink --on-bt-download-complete --ftp-proxy --show-files --show-files=false --timeout --bt-hash-check-seed --bt-hash-check-seed=false --ftp-pasv --ftp-pasv=false --check-certificate --check-certificate=false --always-resume --always-resume=false --load-cookies --bt-remove-unselected-file --bt-remove-unselected-file=false --bt-stop-timeout --version --max-concurrent-downloads --quiet --quiet=false --max-download-result --max-resume-failure-tries --header --rpc-listen-all --rpc-listen-all=false --all-proxy-user --server-stat-if --dht-file-path6 --save-session --bt-external-ip --max-tries --conditional-get --conditional-get=false --ftp-reuse-connection --ftp-reuse-connection=false --gid --dscp --max-download-limit --bt-prioritize-piece --check-integrity --check-integrity=false --log-level --remote-time --remote-time=false --uri-selector --rpc-listen-port --index-out --bt-tracker --referer --ssh-host-key-md --console-log-level --connect-timeout --stream-piece-selector --dht-message-timeout --select-file --download-result --disable-ipv6 --disable-ipv6=false --rpc-max-request-size --rpc-passwd --stop-with-process --https-proxy-passwd --continue --continue=false --no-file-allocation-limit --netrc-path --ftp-proxy-user --enable-color --enable-color=false --metalink-location --allow-piece-length-change --allow-piece-length-change=false --max-connection-per-server --no-conf --no-conf=false --rpc-certificate --metalink-os --enable-http-pipelining --enable-http-pipelining=false --http-passwd --user-agent --enable-dht6 --enable-dht6=false --dht-file-path --http-auth-challenge --http-auth-challenge=false --bt-enable-hook-after-hash-check --bt-enable-hook-after-hash-check=false --peer-id-prefix --max-mmap-limit --enable-mmap --enable-mmap=false --use-head --use-head=false --bt-require-crypto --bt-require-crypto=false --show-console-readout --show-console-readout=false --conf-path --log --no-proxy --dht-entry-point --dht-listen-port --http-user --retry-wait --on-download-complete --help --help=#basic --help=#advanced --help=#http --help=#https --help=#ftp --help=#metalink --help=#bittorrent --help=#cookie --help=#hook --help=#file --help=#rpc --help=#checksum --help=#experimental --help=#deprecated --help=#help --help=#all --max-overall-download-limit --event-poll --http-accept-gzip --http-accept-gzip=false --metalink-file --all-proxy --disk-cache --hash-check-only --hash-check-only=false --dht-listen-addr6 --human-readable --human-readable=false --ftp-user --all-proxy-passwd --bt-exclude-tracker --pause-metadata --pause-metadata=false --http-proxy-user --deferred-input --deferred-input=false --metalink-enable-unique-protocol --metalink-enable-unique-protocol=false --stop --max-upload-limit --multiple-interface --realtime-chunk-checksum --realtime-chunk-checksum=false --http-no-cache --http-no-cache=false --ca-certificate --bt-force-encryption --bt-force-encryption=false --bt-save-metadata --bt-save-metadata=false --seed-ratio --follow-torrent --pause --pause=false --checksum --auto-save-interval --async-dns --async-dns=false --bt-enable-lpd --bt-enable-lpd=false --parameterized-uri --parameterized-uri=false --ftp-proxy-passwd --enable-rpc --enable-rpc=false --min-split-size --bt-seed-unverified --bt-seed-unverified=false --input-file --interface --enable-async-dns6 --enable-async-dns6=false --reuse-uri --reuse-uri=false --socket-recv-buffer-size --bt-request-peer-speed-limit --on-download-error --bt-metadata-only --bt-metadata-only=false ' -- "$cur" ) ) + COMPREPLY=( $( compgen -W '--rpc-save-upload-metadata --rpc-save-upload-metadata=false --on-download-start --metalink-language --rpc-secret --torrent-file --enable-peer-exchange --enable-peer-exchange=false --http-proxy-passwd --bt-tracker-timeout --ftp-type --seed-time --bt-tracker-connect-timeout --bt-max-open-files --no-netrc --no-netrc=false --force-sequential --force-sequential=false --metalink-base-uri --private-key --ftp-passwd --allow-overwrite --allow-overwrite=false --rpc-allow-origin-all --rpc-allow-origin-all=false --bt-detach-seed-only --bt-detach-seed-only=false --dht-entry-point6 --summary-interval --lowest-speed-limit --bt-tracker-interval --proxy-method --metalink-preferred-protocol --enable-http-keep-alive --enable-http-keep-alive=false --metalink-version --stderr --stderr=false --bt-lpd-interface --force-save --force-save=false --rpc-secure --rpc-secure=false --listen-port --rpc-private-key --server-stat-of --server-stat-timeout --https-proxy-user --piece-length --dry-run --dry-run=false --truncate-console-readout --truncate-console-readout=false --async-dns-server --bt-max-peers --max-overall-upload-limit --rpc-user --optimize-concurrent-downloads --optimize-concurrent-downloads=true --optimize-concurrent-downloads=false --optimize-concurrent-downloads=A:B --dir --split --on-download-pause --auto-file-renaming --auto-file-renaming=false --http-proxy --save-session-interval --daemon --daemon=false --https-proxy --min-tls-version --save-cookies --out --rlimit-nofile --max-file-not-found --on-download-stop --certificate --bt-min-crypto-level --remove-control-file --remove-control-file=false --enable-dht --enable-dht=false --file-allocation --follow-metalink --on-bt-download-complete --ftp-proxy --show-files --show-files=false --timeout --bt-hash-check-seed --bt-hash-check-seed=false --ftp-pasv --ftp-pasv=false --check-certificate --check-certificate=false --always-resume --always-resume=false --load-cookies --bt-remove-unselected-file --bt-remove-unselected-file=false --bt-stop-timeout --version --max-concurrent-downloads --quiet --quiet=false --max-download-result --max-resume-failure-tries --header --rpc-listen-all --rpc-listen-all=false --all-proxy-user --server-stat-if --dht-file-path6 --save-session --bt-external-ip --max-tries --conditional-get --conditional-get=false --ftp-reuse-connection --ftp-reuse-connection=false --gid --dscp --max-download-limit --bt-prioritize-piece --check-integrity --check-integrity=false --log-level --remote-time --remote-time=false --uri-selector --rpc-listen-port --index-out --bt-tracker --referer --ssh-host-key-md --console-log-level --connect-timeout --stream-piece-selector --dht-message-timeout --select-file --download-result --disable-ipv6 --disable-ipv6=false --rpc-max-request-size --rpc-passwd --stop-with-process --https-proxy-passwd --continue --continue=false --no-file-allocation-limit --netrc-path --ftp-proxy-user --enable-color --enable-color=false --metalink-location --allow-piece-length-change --allow-piece-length-change=false --max-connection-per-server --no-conf --no-conf=false --rpc-certificate --metalink-os --enable-http-pipelining --enable-http-pipelining=false --http-passwd --user-agent --enable-dht6 --enable-dht6=false --dht-file-path --http-auth-challenge --http-auth-challenge=false --bt-enable-hook-after-hash-check --bt-enable-hook-after-hash-check=false --peer-id-prefix --max-mmap-limit --enable-mmap --enable-mmap=false --use-head --use-head=false --bt-require-crypto --bt-require-crypto=false --show-console-readout --show-console-readout=false --conf-path --log --no-proxy --dht-entry-point --dht-listen-port --http-user --retry-wait --on-download-complete --help --help=#basic --help=#advanced --help=#http --help=#https --help=#ftp --help=#metalink --help=#bittorrent --help=#cookie --help=#hook --help=#file --help=#rpc --help=#checksum --help=#experimental --help=#deprecated --help=#help --help=#all --max-overall-download-limit --event-poll --http-accept-gzip --http-accept-gzip=false --metalink-file --all-proxy --disk-cache --hash-check-only --hash-check-only=false --dht-listen-addr6 --human-readable --human-readable=false --ftp-user --all-proxy-passwd --bt-exclude-tracker --pause-metadata --pause-metadata=false --http-proxy-user --deferred-input --deferred-input=false --metalink-enable-unique-protocol --metalink-enable-unique-protocol=false --stop --max-upload-limit --multiple-interface --realtime-chunk-checksum --realtime-chunk-checksum=false --http-no-cache --http-no-cache=false --ca-certificate --bt-force-encryption --bt-force-encryption=false --bt-save-metadata --bt-save-metadata=false --seed-ratio --follow-torrent --pause --pause=false --checksum --auto-save-interval --async-dns --async-dns=false --bt-enable-lpd --bt-enable-lpd=false --parameterized-uri --parameterized-uri=false --ftp-proxy-passwd --enable-rpc --enable-rpc=false --min-split-size --bt-seed-unverified --bt-seed-unverified=false --input-file --interface --enable-async-dns6 --enable-async-dns6=false --reuse-uri --reuse-uri=false --socket-recv-buffer-size --bt-request-peer-speed-limit --on-download-error --bt-metadata-only --bt-metadata-only=false ' -- "$cur" ) ) ;; *) _filedir '@(torrent|meta4|metalink|text|txt|list|lst)' diff --git a/import-po b/import-po index 5eaf6fd4..49cb8c83 100755 --- a/import-po +++ b/import-po @@ -30,7 +30,7 @@ echo "Renaming po files..." mv "$WORK_DIR"/aria2/*.po "$WORK_DIR" echo -n "en@quot en@boldquot" > "$PO_DIR"/LINGUAS -for file in `ls "$WORK_DIR"/*.po`; do +for file in "$WORK_DIR"/*.po; do # First remove useless '\r' in messages sed -i -e 's/\\r//' "$file" bn=`basename "$file"` diff --git a/po/README.rst b/po/README.rst index 7cc38246..ebffbb84 100644 --- a/po/README.rst +++ b/po/README.rst @@ -21,5 +21,5 @@ Importing PO files from launchpad-export.tar.gz The downloaded file is named as launchpad-export.tar.gz at the time of this writing. It includes all PO files translated at launchpad. To import those files, use ``import-po`` script in the top directory. It -will deflate the tar.gz file and rename PO files and move them to po +will inflate the tar.gz file and rename PO files and move them to po directory and run ``make update-po``. diff --git a/src/AbstractSingleDiskAdaptor.cc b/src/AbstractSingleDiskAdaptor.cc index 470beb37..57881755 100644 --- a/src/AbstractSingleDiskAdaptor.cc +++ b/src/AbstractSingleDiskAdaptor.cc @@ -96,49 +96,10 @@ ssize_t AbstractSingleDiskAdaptor::readDataDropCache(unsigned char* data, void AbstractSingleDiskAdaptor::writeCache(const WrDiskCacheEntry* entry) { - // Write cached data in 4KiB aligned offset. This reduces disk - // activity especially on Windows 7 NTFS. In this code, we assume - // that maximum length of DataCell data is 16KiB to simplify the - // code. - unsigned char buf[16_k]; - int64_t start = 0; - size_t buflen = 0; - size_t buffoffset = 0; - const WrDiskCacheEntry::DataCellSet& dataSet = entry->getDataSet(); - for (auto& d : dataSet) { - if (start + static_cast(buflen) < d->goff) { - A2_LOG_DEBUG(fmt("Cache flush goff=%" PRId64 ", len=%lu", start, - static_cast(buflen))); - writeData(buf + buffoffset, buflen - buffoffset, start); - start = d->goff; - buflen = buffoffset = 0; - } - if (buflen == 0 && (d->goff & 0xfff) == 0 && (d->len & 0xfff) == 0) { - // Already aligned. Write it without copy. - A2_LOG_DEBUG(fmt("Cache flush goff=%" PRId64 ", len=%lu", start, - static_cast(d->len))); - writeData(d->data + d->offset, d->len, start); - start += d->len; - } - else { - if (buflen == 0) { - buflen = buffoffset = d->goff & 0xfff; - } - size_t wlen = std::min(sizeof(buf) - buflen, d->len); - memcpy(buf + buflen, d->data + d->offset, wlen); - buflen += wlen; - if (buflen == sizeof(buf)) { - A2_LOG_DEBUG(fmt("Cache flush goff=%" PRId64 ", len=%lu", start, - static_cast(buflen))); - writeData(buf + buffoffset, buflen - buffoffset, start); - memcpy(buf, d->data + d->offset + wlen, d->len - wlen); - start += sizeof(buf) - buffoffset; - buflen = d->len - wlen; - buffoffset = 0; - } - } + for (auto& d : entry->getDataSet()) { + A2_LOG_DEBUG(fmt("Cache flush goff=%" PRId64 ", len=%lu", d->goff, d->len)); + writeData(d->data + d->offset, d->len, d->goff); } - writeData(buf + buffoffset, buflen - buffoffset, start); } bool AbstractSingleDiskAdaptor::fileExists() diff --git a/src/BtHandshakeMessage.cc b/src/BtHandshakeMessage.cc index c7ebfef1..95f99e0d 100644 --- a/src/BtHandshakeMessage.cc +++ b/src/BtHandshakeMessage.cc @@ -37,16 +37,13 @@ #include #include "util.h" -#include "BtConstants.h" #include "a2functional.h" namespace aria2 { +const unsigned char BtHandshakeMessage::BT_PSTR[] = "BitTorrent protocol"; const char BtHandshakeMessage::NAME[] = "handshake"; -const unsigned char* BtHandshakeMessage::BT_PSTR = - reinterpret_cast("BitTorrent protocol"); - BtHandshakeMessage::BtHandshakeMessage() : SimpleBtMessage(ID, NAME) { init(); } BtHandshakeMessage::BtHandshakeMessage(const unsigned char* infoHash, @@ -54,19 +51,17 @@ BtHandshakeMessage::BtHandshakeMessage(const unsigned char* infoHash, : SimpleBtMessage(ID, NAME) { init(); - memcpy(infoHash_, infoHash, INFO_HASH_LENGTH); - memcpy(peerId_, peerId, PEER_ID_LENGTH); + std::copy_n(infoHash, infoHash_.size(), std::begin(infoHash_)); + std::copy_n(peerId, peerId_.size(), std::begin(peerId_)); } +BtHandshakeMessage::~BtHandshakeMessage() {} + void BtHandshakeMessage::init() { pstrlen_ = 19; - pstr_ = new unsigned char[PSTR_LENGTH]; - reserved_ = new unsigned char[RESERVED_LENGTH]; - infoHash_ = new unsigned char[INFO_HASH_LENGTH]; - peerId_ = new unsigned char[PEER_ID_LENGTH]; - memcpy(pstr_, BT_PSTR, PSTR_LENGTH); - memset(reserved_, 0, RESERVED_LENGTH); + std::copy_n(BT_PSTR, pstr_.size(), std::begin(pstr_)); + std::fill(std::begin(reserved_), std::end(reserved_), 0); // fast extension reserved_[7] |= 0x04u; // extended messaging @@ -76,23 +71,25 @@ void BtHandshakeMessage::init() std::unique_ptr BtHandshakeMessage::create(const unsigned char* data, size_t dataLength) { - auto message = make_unique(); - message->pstrlen_ = data[0]; - memcpy(message->pstr_, &data[1], PSTR_LENGTH); - memcpy(message->reserved_, &data[20], RESERVED_LENGTH); - memcpy(message->infoHash_, &data[28], INFO_HASH_LENGTH); - memcpy(message->peerId_, &data[48], PEER_ID_LENGTH); - return message; + auto msg = make_unique(); + msg->pstrlen_ = data[0]; + std::copy_n(&data[1], msg->pstr_.size(), std::begin(msg->pstr_)); + std::copy_n(&data[20], msg->reserved_.size(), std::begin(msg->reserved_)); + std::copy_n(&data[28], msg->infoHash_.size(), std::begin(msg->infoHash_)); + std::copy_n(&data[48], msg->peerId_.size(), std::begin(msg->peerId_)); + + return msg; } unsigned char* BtHandshakeMessage::createMessage() { auto msg = new unsigned char[MESSAGE_LENGTH]; - msg[0] = pstrlen_; - memcpy(msg + 1, pstr_, PSTR_LENGTH); - memcpy(msg + 20, reserved_, RESERVED_LENGTH); - memcpy(msg + 28, infoHash_, INFO_HASH_LENGTH); - memcpy(msg + 48, peerId_, PEER_ID_LENGTH); + auto dst = msg; + *dst++ = pstrlen_; + dst = std::copy(std::begin(pstr_), std::end(pstr_), dst); + dst = std::copy(std::begin(reserved_), std::end(reserved_), dst); + dst = std::copy(std::begin(infoHash_), std::end(infoHash_), dst); + std::copy(std::begin(peerId_), std::end(peerId_), dst); return msg; } @@ -101,8 +98,8 @@ size_t BtHandshakeMessage::getMessageLength() { return MESSAGE_LENGTH; } std::string BtHandshakeMessage::toString() const { return fmt("%s peerId=%s, reserved=%s", NAME, - util::percentEncode(peerId_, PEER_ID_LENGTH).c_str(), - util::toHex(reserved_, RESERVED_LENGTH).c_str()); + util::percentEncode(peerId_.data(), peerId_.size()).c_str(), + util::toHex(reserved_.data(), reserved_.size()).c_str()); } bool BtHandshakeMessage::isFastExtensionSupported() const @@ -119,12 +116,12 @@ bool BtHandshakeMessage::isDHTEnabled() const { return reserved_[7] & 0x01u; } void BtHandshakeMessage::setInfoHash(const unsigned char* infoHash) { - memcpy(infoHash_, infoHash, INFO_HASH_LENGTH); + std::copy_n(infoHash, infoHash_.size(), std::begin(infoHash_)); } void BtHandshakeMessage::setPeerId(const unsigned char* peerId) { - memcpy(peerId_, peerId, PEER_ID_LENGTH); + std::copy_n(peerId, peerId_.size(), std::begin(peerId_)); } } // namespace aria2 diff --git a/src/BtHandshakeMessage.h b/src/BtHandshakeMessage.h index 51893b57..5bbb0b4f 100644 --- a/src/BtHandshakeMessage.h +++ b/src/BtHandshakeMessage.h @@ -37,21 +37,26 @@ #include "SimpleBtMessage.h" +#include + +#include "BtConstants.h" + namespace aria2 { class BtHandshakeMessage : public SimpleBtMessage { public: - static const size_t PSTR_LENGTH = 19; - static const unsigned char* BT_PSTR; - static const size_t RESERVED_LENGTH = 8; - static const size_t MESSAGE_LENGTH = 68; + constexpr static size_t PSTR_LENGTH = 19; + constexpr static size_t RESERVED_LENGTH = 8; + constexpr static size_t MESSAGE_LENGTH = 68; + const static unsigned char BT_PSTR[]; private: uint8_t pstrlen_; - unsigned char* pstr_; - unsigned char* reserved_; - unsigned char* infoHash_; - unsigned char* peerId_; + std::array pstr_; + std::array reserved_; + std::array infoHash_; + std::array peerId_; + void init(); public: @@ -66,17 +71,11 @@ public: static std::unique_ptr create(const unsigned char* data, size_t dataLength); - virtual ~BtHandshakeMessage() - { - delete[] pstr_; - delete[] reserved_; - delete[] infoHash_; - delete[] peerId_; - } + virtual ~BtHandshakeMessage(); static const uint8_t ID = INT8_MAX; - static const char NAME[]; + const static char NAME[]; virtual void doReceivedAction() CXX11_OVERRIDE{}; @@ -104,15 +103,15 @@ public: uint8_t getPstrlen() const { return pstrlen_; } - const unsigned char* getPstr() const { return pstr_; } + const unsigned char* getPstr() const { return pstr_.data(); } - const unsigned char* getReserved() const { return reserved_; } + const unsigned char* getReserved() const { return reserved_.data(); } - const unsigned char* getInfoHash() const { return infoHash_; } + const unsigned char* getInfoHash() const { return infoHash_.data(); } void setInfoHash(const unsigned char* infoHash); - const unsigned char* getPeerId() const { return peerId_; } + const unsigned char* getPeerId() const { return peerId_.data(); } void setPeerId(const unsigned char* peerId); }; diff --git a/src/DHTGetPeersReplyMessage.cc b/src/DHTGetPeersReplyMessage.cc index 80464810..2ae92f3b 100644 --- a/src/DHTGetPeersReplyMessage.cc +++ b/src/DHTGetPeersReplyMessage.cc @@ -35,6 +35,7 @@ #include "DHTGetPeersReplyMessage.h" #include +#include #include "DHTNode.h" #include "DHTBucket.h" @@ -81,24 +82,24 @@ std::unique_ptr DHTGetPeersReplyMessage::getResponse() rDict->put(TOKEN, token_); // TODO want parameter if (!closestKNodes_.empty()) { - unsigned char buffer[DHTBucket::K * 38]; - const int clen = bittorrent::getCompactLength(family_); - const int unit = clen + 20; - size_t offset = 0; + std::array buffer; + const auto clen = bittorrent::getCompactLength(family_); + const auto unit = clen + DHT_ID_LENGTH; + auto last = std::begin(buffer); size_t k = 0; - for (auto i = std::begin(closestKNodes_), eoi = std::end(closestKNodes_); - i != eoi && k < DHTBucket::K; ++i) { - memcpy(buffer + offset, (*i)->getID(), DHT_ID_LENGTH); - unsigned char compact[COMPACT_LEN_IPV6]; - int compactlen = bittorrent::packcompact(compact, (*i)->getIPAddress(), - (*i)->getPort()); + for (auto i = std::begin(closestKNodes_); + i != std::end(closestKNodes_) && k < DHTBucket::K; ++i) { + std::array compact; + auto compactlen = bittorrent::packcompact( + compact.data(), (*i)->getIPAddress(), (*i)->getPort()); if (compactlen == clen) { - memcpy(buffer + 20 + offset, compact, compactlen); - offset += unit; + last = std::copy_n((*i)->getID(), DHT_ID_LENGTH, last); + last = std::copy_n(std::begin(compact), compactlen, last); ++k; } } - rDict->put(family_ == AF_INET ? NODES : NODES6, String::g(buffer, offset)); + rDict->put(family_ == AF_INET ? NODES : NODES6, + String::g(std::begin(buffer), last)); } if (!values_.empty()) { // Limit the size of values list. The maximum size of UDP datagram @@ -123,16 +124,16 @@ std::unique_ptr DHTGetPeersReplyMessage::getResponse() // doesn't specify the maximum size of token, reply message // template may get bigger than 395 bytes. So we use 25 as maximum // number of peer info that a message can carry. - static const size_t MAX_VALUES_SIZE = 25; + constexpr size_t MAX_VALUES_SIZE = 25; auto valuesList = List::g(); - for (auto i = std::begin(values_), eoi = std::end(values_); - i != eoi && valuesList->size() < MAX_VALUES_SIZE; ++i) { - unsigned char compact[COMPACT_LEN_IPV6]; - const int clen = bittorrent::getCompactLength(family_); - int compactlen = bittorrent::packcompact(compact, (*i)->getIPAddress(), - (*i)->getPort()); + for (auto i = std::begin(values_); + i != std::end(values_) && valuesList->size() < MAX_VALUES_SIZE; ++i) { + std::array compact; + const auto clen = bittorrent::getCompactLength(family_); + auto compactlen = bittorrent::packcompact( + compact.data(), (*i)->getIPAddress(), (*i)->getPort()); if (compactlen == clen) { - valuesList->append(String::g(compact, compactlen)); + valuesList->append(String::g(compact.data(), compactlen)); } } rDict->put(VALUES, std::move(valuesList)); diff --git a/src/MultiDiskAdaptor.cc b/src/MultiDiskAdaptor.cc index 3e6a5ea0..13c7364f 100644 --- a/src/MultiDiskAdaptor.cc +++ b/src/MultiDiskAdaptor.cc @@ -412,98 +412,10 @@ ssize_t MultiDiskAdaptor::readData(unsigned char* data, size_t len, void MultiDiskAdaptor::writeCache(const WrDiskCacheEntry* entry) { - // Write cached data in 4KiB aligned offset. This reduces disk - // activity especially on Windows 7 NTFS. - unsigned char buf[16_k]; - size_t buflen = 0; - size_t buffoffset = 0; - auto& dataSet = entry->getDataSet(); - if (dataSet.empty()) { - return; + for (auto& d : entry->getDataSet()) { + A2_LOG_DEBUG(fmt("Cache flush goff=%" PRId64 ", len=%lu", d->goff, d->len)); + writeData(d->data + d->offset, d->len, d->goff); } - auto dent = - findFirstDiskWriterEntry(diskWriterEntries_, (*dataSet.begin())->goff), - eod = diskWriterEntries_.cend(); - auto i = std::begin(dataSet), eoi = std::end(dataSet); - size_t celloff = 0; - for (; dent != eod; ++dent) { - int64_t lstart = 0, lp = 0; - auto& fent = (*dent)->getFileEntry(); - if (fent->getLength() == 0) { - continue; - } - for (; i != eoi;) { - if (std::max(fent->getOffset(), - static_cast((*i)->goff + celloff)) < - std::min(fent->getLastOffset(), - static_cast((*i)->goff + (*i)->len))) { - openIfNot((*dent).get(), &DiskWriterEntry::openFile); - if (!(*dent)->isOpen()) { - throwOnDiskWriterNotOpened((*dent).get(), (*i)->goff + celloff); - } - } - else { - A2_LOG_DEBUG(fmt("%s Cache flush loff=%" PRId64 ", len=%lu", - fent->getPath().c_str(), lstart, - static_cast(buflen - buffoffset))); - (*dent)->getDiskWriter()->writeData(buf + buffoffset, - buflen - buffoffset, lstart); - buflen = buffoffset = 0; - break; - } - int64_t loff = fent->gtoloff((*i)->goff + celloff); - if (static_cast(lstart + buflen) < loff) { - A2_LOG_DEBUG(fmt("%s Cache flush loff=%" PRId64 ", len=%lu", - fent->getPath().c_str(), lstart, - static_cast(buflen - buffoffset))); - (*dent)->getDiskWriter()->writeData(buf + buffoffset, - buflen - buffoffset, lstart); - lstart = lp = loff; - buflen = buffoffset = 0; - } - // If the position of the cache data is not aligned, offset - // buffer so that next write can be aligned. - if (buflen == 0) { - buflen = buffoffset = loff & 0xfff; - } - assert((*i)->len > celloff); - for (;;) { - size_t wlen = std::min(static_cast((*i)->len - celloff), - fent->getLength() - lp); - wlen = std::min(wlen, sizeof(buf) - buflen); - memcpy(buf + buflen, (*i)->data + (*i)->offset + celloff, wlen); - buflen += wlen; - celloff += wlen; - lp += wlen; - if (lp == fent->getLength() || buflen == sizeof(buf)) { - A2_LOG_DEBUG(fmt("%s Cache flush loff=%" PRId64 ", len=%lu", - fent->getPath().c_str(), lstart, - static_cast(buflen - buffoffset))); - (*dent)->getDiskWriter()->writeData(buf + buffoffset, - buflen - buffoffset, lstart); - lstart += buflen - buffoffset; - lp = lstart; - buflen = buffoffset = 0; - } - if (lp == fent->getLength() || celloff == (*i)->len) { - break; - } - } - if (celloff == (*i)->len) { - ++i; - celloff = 0; - } - } - if (i == eoi) { - A2_LOG_DEBUG(fmt("%s Cache flush loff=%" PRId64 ", len=%lu", - fent->getPath().c_str(), lstart, - static_cast(buflen - buffoffset))); - (*dent)->getDiskWriter()->writeData(buf + buffoffset, buflen - buffoffset, - lstart); - break; - } - } - assert(i == eoi); } bool MultiDiskAdaptor::fileExists() diff --git a/src/NsCookieParser.cc b/src/NsCookieParser.cc index e484df8e..77ca25ab 100644 --- a/src/NsCookieParser.cc +++ b/src/NsCookieParser.cc @@ -69,9 +69,14 @@ std::unique_ptr parseNsCookie(const std::string& cookieStr, return nullptr; } int64_t expiryTime; - if (!util::parseLLIntNoThrow(expiryTime, - std::string(vs[4].first, vs[4].second))) { - return nullptr; + { + // chrome extension uses subsecond resolution for expiry time. + double expiryTimeDouble; + if (!util::parseDoubleNoThrow(expiryTimeDouble, + std::string(vs[4].first, vs[4].second))) { + return nullptr; + } + expiryTime = static_cast(expiryTimeDouble); } if (std::numeric_limits::max() < expiryTime) { expiryTime = std::numeric_limits::max(); diff --git a/src/Sqlite3CookieParserImpl.cc b/src/Sqlite3CookieParserImpl.cc index 5d1ce849..751ead1c 100644 --- a/src/Sqlite3CookieParserImpl.cc +++ b/src/Sqlite3CookieParserImpl.cc @@ -59,8 +59,13 @@ Sqlite3ChromiumCookieParser::~Sqlite3ChromiumCookieParser() {} const char* Sqlite3ChromiumCookieParser::getQuery() const { - return "SELECT host_key, path, secure, expires_utc, name, value, " - "last_access_utc" + // chrome's time is microsecond resolution, and its epoc is Jan 1 + // 00:00:00 +0000 1601, so we have to convert it to second from UNIX + // epoc. 11644473600 is the second between chrome's epoc and UNIX + // epoc. e.g., date +%s -d 'Jan 1 00:00:00 +0000 1601' + return "SELECT host_key, path, secure, expires_utc / 1000000 - 11644473600 " + "as expires_utc, name, value, " + "last_access_utc / 1000000 - 11644473600 as last_access_utc" " FROM cookies"; } diff --git a/src/util.cc b/src/util.cc index a2590235..3c9c19b1 100644 --- a/src/util.cc +++ b/src/util.cc @@ -596,6 +596,33 @@ bool parseLLIntNoThrow(int64_t& res, const std::string& s, int base) } } +bool parseDoubleNoThrow(double& res, const std::string& s) +{ + if (s.empty()) { + return false; + } + + errno = 0; + char* endptr; + auto d = strtod(s.c_str(), &endptr); + + if (errno == ERANGE) { + return false; + } + + if (endptr != s.c_str() + s.size()) { + for (auto i = std::begin(s) + (endptr - s.c_str()); i != std::end(s); ++i) { + if (!isspace(*i)) { + return false; + } + } + } + + res = d; + + return true; +} + SegList parseIntSegments(const std::string& src) { SegList sgl; diff --git a/src/util.h b/src/util.h index 25183b5c..76ecb549 100644 --- a/src/util.h +++ b/src/util.h @@ -280,6 +280,10 @@ bool parseUIntNoThrow(uint32_t& res, const std::string& s, int base = 10); bool parseLLIntNoThrow(int64_t& res, const std::string& s, int base = 10); +// Parses |s| as floating point number, and stores the result into +// |res|. This function returns true if it succeeds. +bool parseDoubleNoThrow(double& res, const std::string& s); + SegList parseIntSegments(const std::string& src); // Parses string which specifies the range of piece index for higher diff --git a/test/CookieStorageTest.cc b/test/CookieStorageTest.cc index b9e741b6..a9966a64 100644 --- a/test/CookieStorageTest.cc +++ b/test/CookieStorageTest.cc @@ -328,10 +328,10 @@ void CookieStorageTest::testLoad() c = cookies[3]; CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c->getName()); CPPUNIT_ASSERT_EQUAL(std::string("1000"), c->getValue()); - CPPUNIT_ASSERT((time_t)INT32_MAX <= c->getExpiryTime()); + CPPUNIT_ASSERT_EQUAL((time_t)1463304912, c->getExpiryTime()); CPPUNIT_ASSERT(c->getPersistent()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); - CPPUNIT_ASSERT_EQUAL(std::string("overflow"), c->getDomain()); + CPPUNIT_ASSERT_EQUAL(std::string("something"), c->getDomain()); CPPUNIT_ASSERT(!c->getSecure()); } diff --git a/test/NsCookieParserTest.cc b/test/NsCookieParserTest.cc index 45d81004..23fb4016 100644 --- a/test/NsCookieParserTest.cc +++ b/test/NsCookieParserTest.cc @@ -69,9 +69,9 @@ void NsCookieParserTest::testParse() c = cookies[3].get(); CPPUNIT_ASSERT_EQUAL(std::string("TAX"), c->getName()); CPPUNIT_ASSERT_EQUAL(std::string("1000"), c->getValue()); - CPPUNIT_ASSERT((time_t)INT32_MAX <= c->getExpiryTime()); + CPPUNIT_ASSERT_EQUAL((time_t)1463304912, c->getExpiryTime()); CPPUNIT_ASSERT(c->getPersistent()); - CPPUNIT_ASSERT_EQUAL(std::string("overflow"), c->getDomain()); + CPPUNIT_ASSERT_EQUAL(std::string("something"), c->getDomain()); CPPUNIT_ASSERT(c->getHostOnly()); CPPUNIT_ASSERT_EQUAL(std::string("/"), c->getPath()); CPPUNIT_ASSERT(!c->getSecure()); diff --git a/test/UtilTest2.cc b/test/UtilTest2.cc index 03a28411..544df0d5 100644 --- a/test/UtilTest2.cc +++ b/test/UtilTest2.cc @@ -66,6 +66,7 @@ class UtilTest2 : public CppUnit::TestFixture { CPPUNIT_TEST(testInPrivateAddress); CPPUNIT_TEST(testSecfmt); CPPUNIT_TEST(testTlsHostnameMatch); + CPPUNIT_TEST(testParseDoubleNoThrow); CPPUNIT_TEST_SUITE_END(); private: @@ -115,6 +116,7 @@ public: void testInPrivateAddress(); void testSecfmt(); void testTlsHostnameMatch(); + void testParseDoubleNoThrow(); }; CPPUNIT_TEST_SUITE_REGISTRATION(UtilTest2); @@ -978,4 +980,21 @@ void UtilTest2::testTlsHostnameMatch() CPPUNIT_ASSERT(!util::tlsHostnameMatch("xn--*.a.b", "xn--c.a.b")); } +void UtilTest2::testParseDoubleNoThrow() +{ + double n; + + CPPUNIT_ASSERT(util::parseDoubleNoThrow(n, " 123 ")); + CPPUNIT_ASSERT_EQUAL(123., n); + + CPPUNIT_ASSERT(util::parseDoubleNoThrow(n, "3.14")); + CPPUNIT_ASSERT_EQUAL(3.14, n); + + CPPUNIT_ASSERT(util::parseDoubleNoThrow(n, "-3.14")); + CPPUNIT_ASSERT_EQUAL(-3.14, n); + + CPPUNIT_ASSERT(!util::parseDoubleNoThrow(n, "")); + CPPUNIT_ASSERT(!util::parseDoubleNoThrow(n, "123x")); +} + } // namespace aria2 diff --git a/test/chromium_cookies.sqlite b/test/chromium_cookies.sqlite index c3e98fc8..e653715b 100644 Binary files a/test/chromium_cookies.sqlite and b/test/chromium_cookies.sqlite differ diff --git a/test/nscookietest.txt b/test/nscookietest.txt index 7b7d9e84..5eed9f33 100644 --- a/test/nscookietest.txt +++ b/test/nscookietest.txt @@ -5,5 +5,5 @@ expired FALSE / FALSE 1000 user me 192.168.0.1 TRUE /cgi-bin FALSE 0 passwd secret badformat -overflow FALSE / FALSE 9223372036854775807 TAX 1000 -.example.org TRUE / FALSE 2147483647 novalue +something FALSE / FALSE 1463304912.5 TAX 1000 +.example.org TRUE / FALSE 2147483647.123 novalue