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>
|
||||
|
||||
Updated man page for bt-prioritize-piece option in -i list.
|
||||
|
|
|
@ -162,6 +162,9 @@
|
|||
/* Define to 1 if you have the `gethostbyname' function. */
|
||||
#undef HAVE_GETHOSTBYNAME
|
||||
|
||||
/* Define to 1 if you have the `getifaddrs' function. */
|
||||
#undef HAVE_GETIFADDRS
|
||||
|
||||
/* Define to 1 if you have the `getpagesize' function. */
|
||||
#undef HAVE_GETPAGESIZE
|
||||
|
||||
|
@ -177,6 +180,9 @@
|
|||
/* Define if you have the iconv() function and it works. */
|
||||
#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. */
|
||||
#undef HAVE_INET_ATON
|
||||
|
||||
|
|
|
@ -7682,7 +7682,8 @@ for ac_header in argz.h \
|
|||
termios.h \
|
||||
unistd.h \
|
||||
utime.h \
|
||||
wchar.h
|
||||
wchar.h \
|
||||
ifaddrs.h
|
||||
do :
|
||||
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"
|
||||
|
@ -14402,6 +14403,7 @@ for ac_func in __argz_count \
|
|||
getcwd \
|
||||
gethostbyaddr \
|
||||
gethostbyname \
|
||||
getifaddrs \
|
||||
getpagesize \
|
||||
inet_ntoa \
|
||||
memchr \
|
||||
|
|
|
@ -214,7 +214,8 @@ AC_CHECK_HEADERS([argz.h \
|
|||
termios.h \
|
||||
unistd.h \
|
||||
utime.h \
|
||||
wchar.h])
|
||||
wchar.h \
|
||||
ifaddrs.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_HEADER_STDBOOL
|
||||
|
@ -263,6 +264,7 @@ AC_CHECK_FUNCS([__argz_count \
|
|||
getcwd \
|
||||
gethostbyaddr \
|
||||
gethostbyname \
|
||||
getifaddrs \
|
||||
getpagesize \
|
||||
inet_ntoa \
|
||||
memchr \
|
||||
|
|
|
@ -240,6 +240,16 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
|
|||
op->addTag(TAG_BASIC);
|
||||
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
|
||||
(PREF_LOG,
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
#include "SocketCore.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
# include <ifaddrs.h>
|
||||
#endif // HAVE_IFADDRS_H
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
@ -51,6 +54,7 @@
|
|||
#include "util.h"
|
||||
#include "TimeA2.h"
|
||||
#include "a2functional.h"
|
||||
#include "LogFactory.h"
|
||||
#ifdef ENABLE_SSL
|
||||
# include "TLSContext.h"
|
||||
#endif // ENABLE_SSL
|
||||
|
@ -83,6 +87,10 @@ SocketCore::PollMethod SocketCore::_pollMethod = SocketCore::POLL_METHOD_SELECT;
|
|||
|
||||
int SocketCore::_protocolFamily = AF_UNSPEC;
|
||||
|
||||
SharedHandle<struct sockaddr_storage> SocketCore::_bindAddr;
|
||||
|
||||
socklen_t SocketCore::_bindAddrLen = 0;
|
||||
|
||||
#ifdef ENABLE_SSL
|
||||
SharedHandle<TLSContext> SocketCore::_tlsContext;
|
||||
|
||||
|
@ -159,46 +167,81 @@ std::string uitos(T value)
|
|||
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)
|
||||
{
|
||||
closeConnection();
|
||||
|
||||
struct addrinfo hints;
|
||||
struct addrinfo* res;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = _protocolFamily;
|
||||
hints.ai_socktype = _sockType;
|
||||
hints.ai_flags = flags;
|
||||
hints.ai_protocol = 0;
|
||||
int s;
|
||||
s = getaddrinfo(0, uitos(port).c_str(), &hints, &res);
|
||||
if(s) {
|
||||
throw DL_ABORT_EX(StringFormat(EX_SOCKET_BIND, gai_strerror(s)).str());
|
||||
if(flags == 0 || _bindAddr.isNull()) {
|
||||
struct addrinfo hints;
|
||||
struct addrinfo* res;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = _protocolFamily;
|
||||
hints.ai_socktype = _sockType;
|
||||
hints.ai_flags = flags;
|
||||
hints.ai_protocol = 0;
|
||||
int s;
|
||||
s = getaddrinfo(0, uitos(port).c_str(), &hints, &res);
|
||||
if(s) {
|
||||
throw DL_ABORT_EX(StringFormat(EX_SOCKET_BIND, gai_strerror(s)).str());
|
||||
}
|
||||
struct addrinfo* rp;
|
||||
for(rp = res; rp; rp = rp->ai_next) {
|
||||
sock_t fd = bindInternal(rp->ai_family, rp->ai_socktype, rp->ai_protocol,
|
||||
rp->ai_addr, rp->ai_addrlen);
|
||||
if(fd == (sock_t) -1) {
|
||||
continue;
|
||||
}
|
||||
sockfd = fd;
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
struct addrinfo* rp;
|
||||
for(rp = res; rp; rp = rp->ai_next) {
|
||||
sock_t fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if(fd == (sock_t) -1) {
|
||||
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;
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(res);
|
||||
if(sockfd == (sock_t) -1) {
|
||||
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()
|
||||
{
|
||||
if(listen(sockfd, 1) == -1) {
|
||||
|
@ -268,6 +311,15 @@ void SocketCore::establishConnection(const std::string& host, uint16_t port)
|
|||
CLOSE(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!_bindAddr.isNull()) {
|
||||
if(::bind(fd, reinterpret_cast<const struct sockaddr*>(_bindAddr.get()),
|
||||
_bindAddrLen) == -1) {
|
||||
CLOSE(fd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
sockfd = fd;
|
||||
// make socket non-blocking mode
|
||||
setNonBlockingMode();
|
||||
|
@ -1073,4 +1125,93 @@ void SocketCore::useSelect()
|
|||
_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
|
||||
|
|
|
@ -92,6 +92,10 @@ private:
|
|||
|
||||
static int _protocolFamily;
|
||||
|
||||
static SharedHandle<struct sockaddr_storage> _bindAddr;
|
||||
|
||||
static socklen_t _bindAddrLen;
|
||||
|
||||
bool blocking;
|
||||
int secure;
|
||||
|
||||
|
@ -124,6 +128,8 @@ private:
|
|||
|
||||
void init();
|
||||
|
||||
void bind(const struct sockaddr* addr, socklen_t addrlen);
|
||||
|
||||
#ifdef HAVE_EPOLL
|
||||
|
||||
void initEPOLL();
|
||||
|
@ -349,6 +355,13 @@ public:
|
|||
{
|
||||
_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
|
||||
|
|
|
@ -208,6 +208,12 @@ downloadresultcode::RESULT main(int argc, char* argv[])
|
|||
MessageDigestHelper::staticSHA1DigestInit();
|
||||
#endif // ENABLE_MESSAGE_DIGEST
|
||||
|
||||
// Bind interface
|
||||
if(!op->get(PREF_INTERFACE).empty()) {
|
||||
std::string interface = op->get(PREF_INTERFACE);
|
||||
SocketCore::bindAddress(interface);
|
||||
}
|
||||
|
||||
#ifdef SIGPIPE
|
||||
util::setGlobalSignalHandler(SIGPIPE, SIG_IGN, 0);
|
||||
#endif
|
||||
|
|
|
@ -175,6 +175,8 @@
|
|||
#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_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_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");
|
||||
// value: true | false
|
||||
const std::string PREF_XML_RPC_LISTEN_ALL("xml-rpc-listen-all");
|
||||
// value: string
|
||||
const std::string PREF_INTERFACE("interface");
|
||||
|
||||
/**
|
||||
* FTP related preferences
|
||||
|
|
|
@ -176,6 +176,8 @@ extern const std::string PREF_ON_DOWNLOAD_COMPLETE;
|
|||
extern const std::string PREF_ON_DOWNLOAD_ERROR;
|
||||
// value: true | false
|
||||
extern const std::string PREF_XML_RPC_LISTEN_ALL;
|
||||
// value: string
|
||||
extern const std::string PREF_INTERFACE;
|
||||
|
||||
/**
|
||||
* 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"\
|
||||
" bytes of each file. SIZE can include K or M(1K =\n"\
|
||||
" 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