mirror of https://github.com/aria2/aria2
2009-12-03 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Added --interface option. This feature binds sockets to given interface. You can specify interface name, IP address and hostname. * configure.ac * src/OptionHandlerFactory.cc * src/SocketCore.cc * src/SocketCore.h * src/main.cc * src/message.h * src/prefs.cc * src/prefs.h * src/usage_text.hpull/1/head
parent
854660005d
commit
4156debe5c
15
ChangeLog
15
ChangeLog
|
@ -1,3 +1,18 @@
|
||||||
|
2009-12-03 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
||||||
|
|
||||||
|
Added --interface option. This feature binds sockets to given
|
||||||
|
interface. You can specify interface name, IP address and
|
||||||
|
hostname.
|
||||||
|
* configure.ac
|
||||||
|
* src/OptionHandlerFactory.cc
|
||||||
|
* src/SocketCore.cc
|
||||||
|
* src/SocketCore.h
|
||||||
|
* src/main.cc
|
||||||
|
* src/message.h
|
||||||
|
* src/prefs.cc
|
||||||
|
* src/prefs.h
|
||||||
|
* src/usage_text.h
|
||||||
|
|
||||||
2009-11-29 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
2009-11-29 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
|
||||||
|
|
||||||
Updated man page for bt-prioritize-piece option in -i list.
|
Updated man page for bt-prioritize-piece option in -i list.
|
||||||
|
|
|
@ -162,6 +162,9 @@
|
||||||
/* Define to 1 if you have the `gethostbyname' function. */
|
/* Define to 1 if you have the `gethostbyname' function. */
|
||||||
#undef HAVE_GETHOSTBYNAME
|
#undef HAVE_GETHOSTBYNAME
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `getifaddrs' function. */
|
||||||
|
#undef HAVE_GETIFADDRS
|
||||||
|
|
||||||
/* Define to 1 if you have the `getpagesize' function. */
|
/* Define to 1 if you have the `getpagesize' function. */
|
||||||
#undef HAVE_GETPAGESIZE
|
#undef HAVE_GETPAGESIZE
|
||||||
|
|
||||||
|
@ -177,6 +180,9 @@
|
||||||
/* Define if you have the iconv() function and it works. */
|
/* Define if you have the iconv() function and it works. */
|
||||||
#undef HAVE_ICONV
|
#undef HAVE_ICONV
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <ifaddrs.h> header file. */
|
||||||
|
#undef HAVE_IFADDRS_H
|
||||||
|
|
||||||
/* Define to 1 if you have the `inet_aton' function. */
|
/* Define to 1 if you have the `inet_aton' function. */
|
||||||
#undef HAVE_INET_ATON
|
#undef HAVE_INET_ATON
|
||||||
|
|
||||||
|
|
|
@ -7682,7 +7682,8 @@ for ac_header in argz.h \
|
||||||
termios.h \
|
termios.h \
|
||||||
unistd.h \
|
unistd.h \
|
||||||
utime.h \
|
utime.h \
|
||||||
wchar.h
|
wchar.h \
|
||||||
|
ifaddrs.h
|
||||||
do :
|
do :
|
||||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||||
ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
|
||||||
|
@ -14402,6 +14403,7 @@ for ac_func in __argz_count \
|
||||||
getcwd \
|
getcwd \
|
||||||
gethostbyaddr \
|
gethostbyaddr \
|
||||||
gethostbyname \
|
gethostbyname \
|
||||||
|
getifaddrs \
|
||||||
getpagesize \
|
getpagesize \
|
||||||
inet_ntoa \
|
inet_ntoa \
|
||||||
memchr \
|
memchr \
|
||||||
|
|
|
@ -214,7 +214,8 @@ AC_CHECK_HEADERS([argz.h \
|
||||||
termios.h \
|
termios.h \
|
||||||
unistd.h \
|
unistd.h \
|
||||||
utime.h \
|
utime.h \
|
||||||
wchar.h])
|
wchar.h \
|
||||||
|
ifaddrs.h])
|
||||||
|
|
||||||
# Checks for typedefs, structures, and compiler characteristics.
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_HEADER_STDBOOL
|
AC_HEADER_STDBOOL
|
||||||
|
@ -263,6 +264,7 @@ AC_CHECK_FUNCS([__argz_count \
|
||||||
getcwd \
|
getcwd \
|
||||||
gethostbyaddr \
|
gethostbyaddr \
|
||||||
gethostbyname \
|
gethostbyname \
|
||||||
|
getifaddrs \
|
||||||
getpagesize \
|
getpagesize \
|
||||||
inet_ntoa \
|
inet_ntoa \
|
||||||
memchr \
|
memchr \
|
||||||
|
|
|
@ -240,6 +240,16 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
|
||||||
op->addTag(TAG_BASIC);
|
op->addTag(TAG_BASIC);
|
||||||
handlers.push_back(op);
|
handlers.push_back(op);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
SharedHandle<OptionHandler> op(new DefaultOptionHandler
|
||||||
|
(PREF_INTERFACE,
|
||||||
|
TEXT_INTERFACE,
|
||||||
|
NO_DEFAULT_VALUE,
|
||||||
|
"interface, IP address, hostname",
|
||||||
|
OptionHandler::REQ_ARG));
|
||||||
|
op->addTag(TAG_ADVANCED);
|
||||||
|
handlers.push_back(op);
|
||||||
|
}
|
||||||
{
|
{
|
||||||
SharedHandle<OptionHandler> op(new DefaultOptionHandler
|
SharedHandle<OptionHandler> op(new DefaultOptionHandler
|
||||||
(PREF_LOG,
|
(PREF_LOG,
|
||||||
|
|
|
@ -35,6 +35,9 @@
|
||||||
#include "SocketCore.h"
|
#include "SocketCore.h"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#ifdef HAVE_IFADDRS_H
|
||||||
|
# include <ifaddrs.h>
|
||||||
|
#endif // HAVE_IFADDRS_H
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -51,6 +54,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "TimeA2.h"
|
#include "TimeA2.h"
|
||||||
#include "a2functional.h"
|
#include "a2functional.h"
|
||||||
|
#include "LogFactory.h"
|
||||||
#ifdef ENABLE_SSL
|
#ifdef ENABLE_SSL
|
||||||
# include "TLSContext.h"
|
# include "TLSContext.h"
|
||||||
#endif // ENABLE_SSL
|
#endif // ENABLE_SSL
|
||||||
|
@ -83,6 +87,10 @@ SocketCore::PollMethod SocketCore::_pollMethod = SocketCore::POLL_METHOD_SELECT;
|
||||||
|
|
||||||
int SocketCore::_protocolFamily = AF_UNSPEC;
|
int SocketCore::_protocolFamily = AF_UNSPEC;
|
||||||
|
|
||||||
|
SharedHandle<struct sockaddr_storage> SocketCore::_bindAddr;
|
||||||
|
|
||||||
|
socklen_t SocketCore::_bindAddrLen = 0;
|
||||||
|
|
||||||
#ifdef ENABLE_SSL
|
#ifdef ENABLE_SSL
|
||||||
SharedHandle<TLSContext> SocketCore::_tlsContext;
|
SharedHandle<TLSContext> SocketCore::_tlsContext;
|
||||||
|
|
||||||
|
@ -159,10 +167,32 @@ std::string uitos(T value)
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static sock_t bindInternal(int family, int socktype, int protocol,
|
||||||
|
const struct sockaddr* addr, socklen_t addrlen)
|
||||||
|
{
|
||||||
|
sock_t fd = socket(family, socktype, protocol);
|
||||||
|
if(fd == (sock_t) -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int sockopt = 1;
|
||||||
|
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (a2_sockopt_t) &sockopt,
|
||||||
|
sizeof(sockopt)) < 0) {
|
||||||
|
CLOSE(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(::bind(fd, addr, addrlen) == -1) {
|
||||||
|
LogFactory::getInstance()->debug("%s", strerror(errno));
|
||||||
|
CLOSE(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
void SocketCore::bind(uint16_t port, int flags)
|
void SocketCore::bind(uint16_t port, int flags)
|
||||||
{
|
{
|
||||||
closeConnection();
|
closeConnection();
|
||||||
|
|
||||||
|
if(flags == 0 || _bindAddr.isNull()) {
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
struct addrinfo* res;
|
struct addrinfo* res;
|
||||||
memset(&hints, 0, sizeof(hints));
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
@ -177,28 +207,41 @@ void SocketCore::bind(uint16_t port, int flags)
|
||||||
}
|
}
|
||||||
struct addrinfo* rp;
|
struct addrinfo* rp;
|
||||||
for(rp = res; rp; rp = rp->ai_next) {
|
for(rp = res; rp; rp = rp->ai_next) {
|
||||||
sock_t fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
sock_t fd = bindInternal(rp->ai_family, rp->ai_socktype, rp->ai_protocol,
|
||||||
|
rp->ai_addr, rp->ai_addrlen);
|
||||||
if(fd == (sock_t) -1) {
|
if(fd == (sock_t) -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int sockopt = 1;
|
|
||||||
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (a2_sockopt_t) &sockopt, sizeof(sockopt)) < 0) {
|
|
||||||
CLOSE(fd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(::bind(fd, rp->ai_addr, rp->ai_addrlen) == -1) {
|
|
||||||
CLOSE(fd);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
sockfd = fd;
|
sockfd = fd;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
freeaddrinfo(res);
|
freeaddrinfo(res);
|
||||||
|
} else {
|
||||||
|
sock_t fd = bindInternal
|
||||||
|
(_bindAddr->ss_family, _sockType, 0,
|
||||||
|
reinterpret_cast<const struct sockaddr*>(_bindAddr.get()), _bindAddrLen);
|
||||||
|
if(fd != (sock_t)-1) {
|
||||||
|
sockfd = fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(sockfd == (sock_t) -1) {
|
if(sockfd == (sock_t) -1) {
|
||||||
throw DL_ABORT_EX(StringFormat(EX_SOCKET_BIND, "all addresses failed").str());
|
throw DL_ABORT_EX(StringFormat(EX_SOCKET_BIND, "all addresses failed").str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SocketCore::bind(const struct sockaddr* addr, socklen_t addrlen)
|
||||||
|
{
|
||||||
|
closeConnection();
|
||||||
|
|
||||||
|
sock_t fd = bindInternal(addr->sa_family, _sockType, 0, addr, addrlen);
|
||||||
|
if(fd != (sock_t)-1) {
|
||||||
|
sockfd = fd;
|
||||||
|
}
|
||||||
|
if(sockfd == (sock_t) -1) {
|
||||||
|
throw DL_ABORT_EX(StringFormat(EX_SOCKET_BIND, strerror(errno)).str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SocketCore::beginListen()
|
void SocketCore::beginListen()
|
||||||
{
|
{
|
||||||
if(listen(sockfd, 1) == -1) {
|
if(listen(sockfd, 1) == -1) {
|
||||||
|
@ -268,6 +311,15 @@ void SocketCore::establishConnection(const std::string& host, uint16_t port)
|
||||||
CLOSE(fd);
|
CLOSE(fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!_bindAddr.isNull()) {
|
||||||
|
if(::bind(fd, reinterpret_cast<const struct sockaddr*>(_bindAddr.get()),
|
||||||
|
_bindAddrLen) == -1) {
|
||||||
|
CLOSE(fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sockfd = fd;
|
sockfd = fd;
|
||||||
// make socket non-blocking mode
|
// make socket non-blocking mode
|
||||||
setNonBlockingMode();
|
setNonBlockingMode();
|
||||||
|
@ -1073,4 +1125,93 @@ void SocketCore::useSelect()
|
||||||
_pollMethod = SocketCore::POLL_METHOD_SELECT;
|
_pollMethod = SocketCore::POLL_METHOD_SELECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SocketCore::bindAddress(const std::string& interface)
|
||||||
|
{
|
||||||
|
SharedHandle<struct sockaddr_storage> bindAddr(new struct sockaddr_storage());
|
||||||
|
socklen_t bindAddrLen = 0;
|
||||||
|
memset(bindAddr.get(), 0, sizeof(struct sockaddr_storage));
|
||||||
|
bool found = false;
|
||||||
|
#ifdef HAVE_GETIFADDRS
|
||||||
|
// First find interface in interface addresses
|
||||||
|
struct ifaddrs* ifaddr = 0;
|
||||||
|
if(getifaddrs(&ifaddr) == -1) {
|
||||||
|
throw DL_ABORT_EX
|
||||||
|
(StringFormat(MSG_INTERFACE_NOT_FOUND,
|
||||||
|
interface.c_str(), strerror(errno)).str());
|
||||||
|
} else {
|
||||||
|
auto_delete<struct ifaddrs*> ifaddrDeleter(ifaddr, freeifaddrs);
|
||||||
|
for(struct ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
||||||
|
if(!ifa->ifa_addr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int family = ifa->ifa_addr->sa_family;
|
||||||
|
if(_protocolFamily == AF_UNSPEC) {
|
||||||
|
if(family != AF_INET && family != AF_INET6) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if(_protocolFamily == AF_INET) {
|
||||||
|
if(family != AF_INET) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if(_protocolFamily == AF_INET6) {
|
||||||
|
if(family != AF_INET6) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(std::string(ifa->ifa_name) == interface) {
|
||||||
|
bindAddrLen =
|
||||||
|
family == AF_INET?sizeof(struct sockaddr_in):
|
||||||
|
sizeof(struct sockaddr_in6);
|
||||||
|
memcpy(bindAddr.get(), ifa->ifa_addr, bindAddrLen);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // HAVE_GETIFADDRS
|
||||||
|
if(!found) {
|
||||||
|
struct addrinfo hints;
|
||||||
|
struct addrinfo* res = 0;
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = _protocolFamily;
|
||||||
|
hints.ai_socktype = 0;
|
||||||
|
hints.ai_flags = 0;
|
||||||
|
hints.ai_protocol = 0;
|
||||||
|
int s;
|
||||||
|
s = getaddrinfo(interface.c_str(), 0, &hints, &res);
|
||||||
|
if(s) {
|
||||||
|
throw DL_ABORT_EX
|
||||||
|
(StringFormat(MSG_INTERFACE_NOT_FOUND,
|
||||||
|
interface.c_str(), gai_strerror(s)).str());
|
||||||
|
} else {
|
||||||
|
auto_delete<struct addrinfo*> resDeleter(res, freeaddrinfo);
|
||||||
|
struct addrinfo* rp;
|
||||||
|
for(rp = res; rp; rp = rp->ai_next) {
|
||||||
|
bindAddrLen = rp->ai_addrlen;
|
||||||
|
memcpy(bindAddr.get(), rp->ai_addr, rp->ai_addrlen);
|
||||||
|
// Try to bind socket with this address. If it fails, the
|
||||||
|
// address is not for this machine.
|
||||||
|
try {
|
||||||
|
SocketCore socket;
|
||||||
|
socket.bind
|
||||||
|
(reinterpret_cast<const struct sockaddr*>(bindAddr.get()),
|
||||||
|
bindAddrLen);
|
||||||
|
} catch(RecoverableException& e) {
|
||||||
|
throw DL_ABORT_EX2
|
||||||
|
(StringFormat(MSG_INTERFACE_NOT_FOUND,
|
||||||
|
interface.c_str()).str(), e);
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(found) {
|
||||||
|
_bindAddr = bindAddr;
|
||||||
|
_bindAddrLen = bindAddrLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -92,6 +92,10 @@ private:
|
||||||
|
|
||||||
static int _protocolFamily;
|
static int _protocolFamily;
|
||||||
|
|
||||||
|
static SharedHandle<struct sockaddr_storage> _bindAddr;
|
||||||
|
|
||||||
|
static socklen_t _bindAddrLen;
|
||||||
|
|
||||||
bool blocking;
|
bool blocking;
|
||||||
int secure;
|
int secure;
|
||||||
|
|
||||||
|
@ -124,6 +128,8 @@ private:
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
|
void bind(const struct sockaddr* addr, socklen_t addrlen);
|
||||||
|
|
||||||
#ifdef HAVE_EPOLL
|
#ifdef HAVE_EPOLL
|
||||||
|
|
||||||
void initEPOLL();
|
void initEPOLL();
|
||||||
|
@ -349,6 +355,13 @@ public:
|
||||||
{
|
{
|
||||||
_protocolFamily = protocolFamily;
|
_protocolFamily = protocolFamily;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bind socket to interface. interface may be specified as a
|
||||||
|
// hostname, IP address or interface name like eth0. If the given
|
||||||
|
// interface is not found or binding socket is failed, exception
|
||||||
|
// will be thrown. Set _protocolFamily before calling this function
|
||||||
|
// if you limit protocol family.
|
||||||
|
static void bindAddress(const std::string& interface);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -208,6 +208,12 @@ downloadresultcode::RESULT main(int argc, char* argv[])
|
||||||
MessageDigestHelper::staticSHA1DigestInit();
|
MessageDigestHelper::staticSHA1DigestInit();
|
||||||
#endif // ENABLE_MESSAGE_DIGEST
|
#endif // ENABLE_MESSAGE_DIGEST
|
||||||
|
|
||||||
|
// Bind interface
|
||||||
|
if(!op->get(PREF_INTERFACE).empty()) {
|
||||||
|
std::string interface = op->get(PREF_INTERFACE);
|
||||||
|
SocketCore::bindAddress(interface);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SIGPIPE
|
#ifdef SIGPIPE
|
||||||
util::setGlobalSignalHandler(SIGPIPE, SIG_IGN, 0);
|
util::setGlobalSignalHandler(SIGPIPE, SIG_IGN, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -175,6 +175,8 @@
|
||||||
#define MSG_CANNOT_PARSE_XML_RPC_REQUEST "Failed to parse xml-rpc request."
|
#define MSG_CANNOT_PARSE_XML_RPC_REQUEST "Failed to parse xml-rpc request."
|
||||||
#define MSG_GOOD_BYE_SEEDER "Client is in seed state: Good Bye Seeder;)"
|
#define MSG_GOOD_BYE_SEEDER "Client is in seed state: Good Bye Seeder;)"
|
||||||
#define MSG_NOT_FILE _("Is '%s' a file?")
|
#define MSG_NOT_FILE _("Is '%s' a file?")
|
||||||
|
#define MSG_INTERFACE_NOT_FOUND _("Failed to find given interface %s,"\
|
||||||
|
" cause: %s")
|
||||||
|
|
||||||
#define EX_TIME_OUT _("Timeout.")
|
#define EX_TIME_OUT _("Timeout.")
|
||||||
#define EX_INVALID_CHUNK_SIZE _("Invalid chunk size.")
|
#define EX_INVALID_CHUNK_SIZE _("Invalid chunk size.")
|
||||||
|
|
|
@ -172,6 +172,8 @@ const std::string PREF_ON_DOWNLOAD_COMPLETE("on-download-complete");
|
||||||
const std::string PREF_ON_DOWNLOAD_ERROR("on-download-error");
|
const std::string PREF_ON_DOWNLOAD_ERROR("on-download-error");
|
||||||
// value: true | false
|
// value: true | false
|
||||||
const std::string PREF_XML_RPC_LISTEN_ALL("xml-rpc-listen-all");
|
const std::string PREF_XML_RPC_LISTEN_ALL("xml-rpc-listen-all");
|
||||||
|
// value: string
|
||||||
|
const std::string PREF_INTERFACE("interface");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FTP related preferences
|
* FTP related preferences
|
||||||
|
|
|
@ -176,6 +176,8 @@ extern const std::string PREF_ON_DOWNLOAD_COMPLETE;
|
||||||
extern const std::string PREF_ON_DOWNLOAD_ERROR;
|
extern const std::string PREF_ON_DOWNLOAD_ERROR;
|
||||||
// value: true | false
|
// value: true | false
|
||||||
extern const std::string PREF_XML_RPC_LISTEN_ALL;
|
extern const std::string PREF_XML_RPC_LISTEN_ALL;
|
||||||
|
// value: string
|
||||||
|
extern const std::string PREF_INTERFACE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FTP related preferences
|
* FTP related preferences
|
||||||
|
|
|
@ -575,3 +575,6 @@ _(" --bt-prioritize-piece=head[=SIZE],tail[=SIZE] Try to download first and last
|
||||||
" priority. tail=SIZE means the range of last SIZE\n"\
|
" priority. tail=SIZE means the range of last SIZE\n"\
|
||||||
" bytes of each file. SIZE can include K or M(1K =\n"\
|
" bytes of each file. SIZE can include K or M(1K =\n"\
|
||||||
" 1024, 1M = 1024K).")
|
" 1024, 1M = 1024K).")
|
||||||
|
#define TEXT_INTERFACE \
|
||||||
|
_(" --interface=INTERFACE Bind sockets to given interface. You can specify\n"\
|
||||||
|
" interface name, IP address and hostname.")
|
||||||
|
|
Loading…
Reference in New Issue