mirror of https://github.com/aria2/aria2
2008-02-20 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
IPv6 support for SocketCore class. TODO: In SocketCore::establishConnection(), this is insufficient to determin the failure of connect() here because the socket is non-blocking state. The next addresses should be tried after select(). TODO: NameResolver still uses c-ares(<= 1.4) ares_gethostbyname(). If c-ares 1.5 or newer is installed, ares_getaddrinfo() should be used instead which address family independent. TODO: DHTRoutingTable{Deserializer,Serializer} currently saves peer information in a compact peer format which is for IPv4 only. Some BitTorrent functions in PeerMessageUtil still depends on IPv4 but this is a spec of BitTorrent protocol. * src/SocketCore.{h, cc} * src/PeerMessageUtil.cc * test/SocketCoreTest.cc * test/PeerMessageUtilTest.cc * test/DHTConnectionImplTest.cc Handle IPv4-mapped addresses. * src/DHTNode.cc: Now identity is determined by node id. * src/DHTMessageTrackerEntry.cc Because now PeerMessageUtil::unpackcompact() could fail, the caller should handle it. * src/DHTRoutingTableDeserializer.cc * src/DHTMessageFactoryImpl.ccpull/1/head
parent
4708809094
commit
2cc471ebf6
29
ChangeLog
29
ChangeLog
|
@ -1,3 +1,32 @@
|
||||||
|
2008-02-20 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||||
|
|
||||||
|
IPv6 support for SocketCore class.
|
||||||
|
TODO: In SocketCore::establishConnection(), this is insufficient to
|
||||||
|
determin the failure of connect() here because the socket is
|
||||||
|
non-blocking state. The next addresses should be tried after select().
|
||||||
|
TODO: NameResolver still uses c-ares(<= 1.4) ares_gethostbyname().
|
||||||
|
If c-ares 1.5 or newer is installed, ares_getaddrinfo() should be used
|
||||||
|
instead which address family independent.
|
||||||
|
TODO: DHTRoutingTable{Deserializer,Serializer} currently saves peer
|
||||||
|
information in a compact peer format which is for IPv4 only.
|
||||||
|
|
||||||
|
Some BitTorrent functions in PeerMessageUtil still depends on IPv4 but
|
||||||
|
this is a spec of BitTorrent protocol.
|
||||||
|
* src/SocketCore.{h, cc}
|
||||||
|
* src/PeerMessageUtil.cc
|
||||||
|
* test/SocketCoreTest.cc
|
||||||
|
* test/PeerMessageUtilTest.cc
|
||||||
|
* test/DHTConnectionImplTest.cc
|
||||||
|
|
||||||
|
Handle IPv4-mapped addresses.
|
||||||
|
* src/DHTNode.cc: Now identity is determined by node id.
|
||||||
|
* src/DHTMessageTrackerEntry.cc
|
||||||
|
|
||||||
|
Because now PeerMessageUtil::unpackcompact() could fail, the caller
|
||||||
|
should handle it.
|
||||||
|
* src/DHTRoutingTableDeserializer.cc
|
||||||
|
* src/DHTMessageFactoryImpl.cc
|
||||||
|
|
||||||
2008-02-20 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
2008-02-20 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
|
||||||
|
|
||||||
Change the unit of --stop option from a minute to a second.
|
Change the unit of --stop option from a minute to a second.
|
||||||
|
|
|
@ -299,6 +299,9 @@ std::deque<SharedHandle<DHTNode> > DHTMessageFactoryImpl::extractNodes(const cha
|
||||||
SharedHandle<DHTNode> node = new DHTNode(reinterpret_cast<const unsigned char*>(src+offset));
|
SharedHandle<DHTNode> node = new DHTNode(reinterpret_cast<const unsigned char*>(src+offset));
|
||||||
std::pair<std::string, uint16_t> addr =
|
std::pair<std::string, uint16_t> addr =
|
||||||
PeerMessageUtil::unpackcompact(src+offset+DHT_ID_LENGTH);
|
PeerMessageUtil::unpackcompact(src+offset+DHT_ID_LENGTH);
|
||||||
|
if(addr.first.empty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
node->setIPAddress(addr.first);
|
node->setIPAddress(addr.first);
|
||||||
node->setPort(addr.second);
|
node->setPort(addr.second);
|
||||||
nodes.push_back(node);
|
nodes.push_back(node);
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "DHTMessage.h"
|
#include "DHTMessage.h"
|
||||||
#include "DHTMessageCallback.h"
|
#include "DHTMessageCallback.h"
|
||||||
#include "DHTConstants.h"
|
#include "DHTConstants.h"
|
||||||
|
#include "Util.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -60,8 +61,18 @@ void DHTMessageTrackerEntry::extendTimeout()
|
||||||
|
|
||||||
bool DHTMessageTrackerEntry::match(const std::string& transactionID, const std::string& ipaddr, uint16_t port) const
|
bool DHTMessageTrackerEntry::match(const std::string& transactionID, const std::string& ipaddr, uint16_t port) const
|
||||||
{
|
{
|
||||||
return _transactionID == transactionID &&
|
if(_transactionID != transactionID || _targetNode->getPort() != port) {
|
||||||
_targetNode->getIPAddress() == ipaddr && _targetNode->getPort() == port;
|
return false;
|
||||||
|
}
|
||||||
|
if(_targetNode->getIPAddress() == ipaddr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(Util::endsWith(_targetNode->getIPAddress(), ipaddr)) {
|
||||||
|
return _targetNode->getIPAddress() == "::ffff:"+ipaddr;
|
||||||
|
} else if(Util::endsWith(ipaddr, _targetNode->getIPAddress())) {
|
||||||
|
return ipaddr == "::ffff:"+_targetNode->getIPAddress();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedHandle<DHTMessageCallback> DHTMessageTrackerEntry::getCallback() const
|
SharedHandle<DHTMessageCallback> DHTMessageTrackerEntry::getCallback() const
|
||||||
|
|
|
@ -56,8 +56,7 @@ void DHTNode::generateID()
|
||||||
|
|
||||||
bool DHTNode::operator==(const DHTNode& node) const
|
bool DHTNode::operator==(const DHTNode& node) const
|
||||||
{
|
{
|
||||||
return memcmp(_id, node._id, DHT_ID_LENGTH) == 0 &&
|
return memcmp(_id, node._id, DHT_ID_LENGTH) == 0;
|
||||||
_ipaddr == node._ipaddr && _port == node._port;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DHTNode::operator<(const DHTNode& node) const
|
bool DHTNode::operator<(const DHTNode& node) const
|
||||||
|
|
|
@ -116,6 +116,11 @@ void DHTRoutingTableDeserializer::deserialize(std::istream& in)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::pair<std::string, uint16_t> peer = PeerMessageUtil::unpackcompact(buf);
|
std::pair<std::string, uint16_t> peer = PeerMessageUtil::unpackcompact(buf);
|
||||||
|
if(peer.first.empty()) {
|
||||||
|
// skip this entry
|
||||||
|
in.read(buf, 26);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// 2bytes reserved
|
// 2bytes reserved
|
||||||
in.read(buf, 2);
|
in.read(buf, 2);
|
||||||
// localnode ID
|
// localnode ID
|
||||||
|
|
|
@ -127,24 +127,40 @@ void PeerMessageUtil::createPeerMessageString(unsigned char* msg,
|
||||||
|
|
||||||
bool PeerMessageUtil::createcompact(char* compact, const std::string& addr, uint16_t port)
|
bool PeerMessageUtil::createcompact(char* compact, const std::string& addr, uint16_t port)
|
||||||
{
|
{
|
||||||
struct in_addr in;
|
struct addrinfo hints;
|
||||||
if(inet_aton(addr.c_str(), &in) == 0) {
|
struct addrinfo* res;
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_INET; // since compact peer format is ipv4 only.
|
||||||
|
hints.ai_flags = AI_NUMERICHOST;
|
||||||
|
if(getaddrinfo(addr.c_str(), 0, &hints, &res)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
struct sockaddr_in* in = reinterpret_cast<struct sockaddr_in*>(res->ai_addr);
|
||||||
uint32_t* addrp = (uint32_t*)compact;
|
uint32_t* addrp = (uint32_t*)compact;
|
||||||
*addrp = in.s_addr;
|
*addrp = in->sin_addr.s_addr;
|
||||||
uint16_t* portp = (uint16_t*)(compact+4);
|
uint16_t* portp = (uint16_t*)(compact+4);
|
||||||
*portp = htons(port);
|
*portp = htons(port);
|
||||||
|
freeaddrinfo(res);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::string, uint16_t> PeerMessageUtil::unpackcompact(const char* compact)
|
std::pair<std::string, uint16_t> PeerMessageUtil::unpackcompact(const char* compact)
|
||||||
{
|
{
|
||||||
struct in_addr in;
|
struct sockaddr_in in;
|
||||||
in.s_addr = *(uint32_t*)(compact);
|
memset(&in, 0, sizeof(in));
|
||||||
std::string ipaddr = inet_ntoa(in);
|
in.sin_family = AF_INET;
|
||||||
|
in.sin_addr.s_addr = *reinterpret_cast<const uint32_t*>(compact);
|
||||||
|
in.sin_port = 0;
|
||||||
|
char host[NI_MAXHOST];
|
||||||
|
int s;
|
||||||
|
s = getnameinfo(reinterpret_cast<const struct sockaddr*>(&in), sizeof(in),
|
||||||
|
host, NI_MAXHOST, 0, NI_MAXSERV,
|
||||||
|
NI_NUMERICHOST);
|
||||||
|
if(s) {
|
||||||
|
return std::pair<std::string, uint16_t>();
|
||||||
|
}
|
||||||
uint16_t port = ntohs(*(uint16_t*)(compact+sizeof(uint32_t)));
|
uint16_t port = ntohs(*(uint16_t*)(compact+sizeof(uint32_t)));
|
||||||
return std::pair<std::string, uint16_t>(ipaddr, port);
|
return std::pair<std::string, uint16_t>(host, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -47,6 +47,18 @@
|
||||||
# define SOCKET_ERRNO (WSAGetLastError())
|
# define SOCKET_ERRNO (WSAGetLastError())
|
||||||
#endif // __MINGW32__
|
#endif // __MINGW32__
|
||||||
|
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
# define A2_EINPROGRESS WSAEWOULDBLOCK
|
||||||
|
#else
|
||||||
|
# define A2_EINPROGRESS EINPROGRESS
|
||||||
|
#endif // __MINGW32__
|
||||||
|
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
# define CLOSE(X) ::closesocket(sockfd)
|
||||||
|
#else
|
||||||
|
# define CLOSE(X) while(close(X) == -1 && errno == EINTR)
|
||||||
|
#endif // __MINGW32__
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
SocketCore::SocketCore(int sockType):_sockType(sockType), sockfd(-1) {
|
SocketCore::SocketCore(int sockType):_sockType(sockType), sockfd(-1) {
|
||||||
|
@ -83,33 +95,61 @@ SocketCore::~SocketCore() {
|
||||||
#endif // HAVE_LIBGNUTLS
|
#endif // HAVE_LIBGNUTLS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::string uitos(T value)
|
||||||
|
{
|
||||||
|
std::string str;
|
||||||
|
if(value == 0) {
|
||||||
|
str = "0";
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
int32_t count = 0;
|
||||||
|
while(value) {
|
||||||
|
++count;
|
||||||
|
char digit = value%10+'0';
|
||||||
|
str.insert(str.begin(), digit);
|
||||||
|
value /= 10;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
void SocketCore::bind(uint16_t port)
|
void SocketCore::bind(uint16_t port)
|
||||||
{
|
{
|
||||||
closeConnection();
|
closeConnection();
|
||||||
//sockfd = socket(AF_UNSPEC, _sockType, PF_UNSPEC);
|
|
||||||
sockfd = socket(AF_INET, _sockType, 0);
|
|
||||||
if(sockfd == -1) {
|
|
||||||
throw new DlAbortEx(EX_SOCKET_OPEN, errorMsg());
|
|
||||||
}
|
|
||||||
SOCKOPT_T sockopt = 1;
|
|
||||||
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(socklen_t)) < 0) {
|
|
||||||
#ifdef __MINGW32__
|
|
||||||
::closesocket(sockfd);
|
|
||||||
#else
|
|
||||||
while(close(sockfd) == -1 && errno == EINTR);
|
|
||||||
#endif // __MINGW32__
|
|
||||||
sockfd = -1;
|
|
||||||
throw new DlAbortEx(EX_SOCKET_SET_OPT, errorMsg());
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sockaddr_in sockaddr;
|
struct addrinfo hints;
|
||||||
memset((char*)&sockaddr, 0, sizeof(sockaddr));
|
struct addrinfo* res;
|
||||||
sockaddr.sin_family = AF_INET;
|
memset(&hints, 0, sizeof(hints));
|
||||||
sockaddr.sin_addr.s_addr = INADDR_ANY;
|
hints.ai_family = AF_UNSPEC;
|
||||||
sockaddr.sin_port = htons(port);
|
hints.ai_socktype = _sockType;
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
if(::bind(sockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == -1) {
|
hints.ai_protocol = 0;
|
||||||
throw new DlAbortEx(EX_SOCKET_BIND, errorMsg());
|
int s;
|
||||||
|
s = getaddrinfo(0, uitos(port).c_str(), &hints, &res);
|
||||||
|
if(s) {
|
||||||
|
throw new DlAbortEx(EX_SOCKET_BIND, gai_strerror(s));
|
||||||
|
}
|
||||||
|
struct addrinfo* rp;
|
||||||
|
for(rp = res; rp; rp = rp->ai_next) {
|
||||||
|
int fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||||
|
if(fd == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SOCKOPT_T sockopt = 1;
|
||||||
|
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(socklen_t)) < 0) {
|
||||||
|
CLOSE(fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(::bind(fd, rp->ai_addr, rp->ai_addrlen) == -1) {
|
||||||
|
CLOSE(fd);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sockfd = fd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
freeaddrinfo(res);
|
||||||
|
if(sockfd == -1) {
|
||||||
|
throw new DlAbortEx(EX_SOCKET_BIND, "all addresses failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,89 +162,95 @@ void SocketCore::beginListen()
|
||||||
|
|
||||||
SocketCore* SocketCore::acceptConnection() const
|
SocketCore* SocketCore::acceptConnection() const
|
||||||
{
|
{
|
||||||
struct sockaddr_in sockaddr;
|
struct sockaddr_storage sockaddr;
|
||||||
socklen_t len = sizeof(sockaddr);
|
socklen_t len = sizeof(sockaddr);
|
||||||
memset((char*)&sockaddr, 0, sizeof(sockaddr));
|
int fd;
|
||||||
int32_t fd;
|
while((fd = accept(sockfd, reinterpret_cast<struct sockaddr*>(&sockaddr), &len)) == -1 && errno == EINTR);
|
||||||
while((fd = accept(sockfd, (struct sockaddr*)&sockaddr, &len)) == -1 && errno == EINTR);
|
|
||||||
if(fd == -1) {
|
if(fd == -1) {
|
||||||
throw new DlAbortEx(EX_SOCKET_ACCEPT, errorMsg());
|
throw new DlAbortEx(EX_SOCKET_ACCEPT, errorMsg());
|
||||||
}
|
}
|
||||||
SocketCore* s = new SocketCore(fd, _sockType);
|
return new SocketCore(fd, _sockType);
|
||||||
return s;
|
}
|
||||||
|
|
||||||
|
std::pair<std::string, uint16_t>
|
||||||
|
SocketCore::getNameInfoInNumeric(const struct sockaddr* sockaddr, socklen_t len)
|
||||||
|
{
|
||||||
|
char host[NI_MAXHOST];
|
||||||
|
char service[NI_MAXSERV];
|
||||||
|
int s = getnameinfo(sockaddr, len, host, NI_MAXHOST, service, NI_MAXSERV,
|
||||||
|
NI_NUMERICHOST|NI_NUMERICSERV);
|
||||||
|
if(s != 0) {
|
||||||
|
throw new DlAbortEx("Failed to get hostname and port. cause: %s",
|
||||||
|
gai_strerror(s));
|
||||||
|
}
|
||||||
|
return std::pair<std::string, uint16_t>(host, atoi(service)); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketCore::getAddrInfo(std::pair<std::string, int32_t>& addrinfo) const
|
void SocketCore::getAddrInfo(std::pair<std::string, int32_t>& addrinfo) const
|
||||||
{
|
{
|
||||||
struct sockaddr_in listenaddr;
|
struct sockaddr_storage sockaddr;
|
||||||
memset((char*)&listenaddr, 0, sizeof(listenaddr));
|
socklen_t len = sizeof(sockaddr);
|
||||||
socklen_t len = sizeof(listenaddr);
|
struct sockaddr* addrp = reinterpret_cast<struct sockaddr*>(&sockaddr);
|
||||||
if(getsockname(sockfd, (struct sockaddr*)&listenaddr, &len) == -1) {
|
if(getsockname(sockfd, addrp, &len) == -1) {
|
||||||
throw new DlAbortEx(EX_SOCKET_GET_NAME, errorMsg());
|
throw new DlAbortEx(EX_SOCKET_GET_NAME, errorMsg());
|
||||||
}
|
}
|
||||||
addrinfo.first = inet_ntoa(listenaddr.sin_addr);
|
addrinfo = SocketCore::getNameInfoInNumeric(addrp, len);
|
||||||
addrinfo.second = ntohs(listenaddr.sin_port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketCore::getPeerInfo(std::pair<std::string, int32_t>& peerinfo) const
|
void SocketCore::getPeerInfo(std::pair<std::string, int32_t>& peerinfo) const
|
||||||
{
|
{
|
||||||
struct sockaddr_in peerin;
|
struct sockaddr_storage sockaddr;
|
||||||
memset(&peerin, 0, sizeof(peerin));
|
socklen_t len = sizeof(sockaddr);
|
||||||
int32_t len = sizeof(peerin);
|
struct sockaddr* addrp = reinterpret_cast<struct sockaddr*>(&sockaddr);
|
||||||
if(getpeername(sockfd, (struct sockaddr*)&peerin, (socklen_t*)&len) < 0) {
|
if(getpeername(sockfd, addrp, &len) == -1) {
|
||||||
throw new DlAbortEx(EX_SOCKET_GET_PEER, errorMsg());
|
throw new DlAbortEx(EX_SOCKET_GET_NAME, errorMsg());
|
||||||
}
|
}
|
||||||
peerinfo.first = inet_ntoa(peerin.sin_addr);
|
peerinfo = SocketCore::getNameInfoInNumeric(addrp, len);
|
||||||
peerinfo.second = ntohs(peerin.sin_port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketCore::establishConnection(const std::string& host, int32_t port)
|
void SocketCore::establishConnection(const std::string& host, int32_t port)
|
||||||
{
|
{
|
||||||
closeConnection();
|
closeConnection();
|
||||||
sockfd = socket(AF_INET, _sockType, 0);
|
|
||||||
if(sockfd == -1) {
|
|
||||||
throw new DlAbortEx(EX_SOCKET_OPEN, errorMsg());
|
|
||||||
}
|
|
||||||
SOCKOPT_T sockopt = 1;
|
|
||||||
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(socklen_t)) < 0) {
|
|
||||||
while(close(sockfd) == -1 && errno == EINTR);
|
|
||||||
sockfd = -1;
|
|
||||||
throw new DlAbortEx(EX_SOCKET_SET_OPT, errorMsg());
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sockaddr_in sockaddr;
|
struct addrinfo hints;
|
||||||
memset((char*)&sockaddr, 0, sizeof(sockaddr));
|
struct addrinfo* res;
|
||||||
sockaddr.sin_family = AF_INET;
|
memset(&hints, 0, sizeof(hints));
|
||||||
sockaddr.sin_port = htons(port);
|
hints.ai_family = AF_UNSPEC;
|
||||||
if(inet_aton(host.c_str(), &sockaddr.sin_addr)) {
|
hints.ai_socktype = _sockType;
|
||||||
// ok
|
hints.ai_flags = 0;
|
||||||
} else {
|
hints.ai_protocol = 0;
|
||||||
struct addrinfo ai;
|
int s;
|
||||||
memset((char*)&ai, 0, sizeof(ai));
|
s = getaddrinfo(host.c_str(), uitos(port).c_str(), &hints, &res);
|
||||||
ai.ai_flags = 0;
|
if(s) {
|
||||||
ai.ai_family = PF_INET;
|
throw new DlAbortEx(EX_RESOLVE_HOSTNAME, host.c_str(), gai_strerror(s));
|
||||||
ai.ai_socktype = _sockType;
|
|
||||||
ai.ai_protocol = 0;
|
|
||||||
struct addrinfo* res;
|
|
||||||
int32_t ec;
|
|
||||||
if((ec = getaddrinfo(host.c_str(), NULL, &ai, &res)) != 0) {
|
|
||||||
throw new DlAbortEx(EX_RESOLVE_HOSTNAME,
|
|
||||||
host.c_str(), gai_strerror(ec));
|
|
||||||
}
|
|
||||||
sockaddr.sin_addr = ((struct sockaddr_in*)res->ai_addr)->sin_addr;
|
|
||||||
freeaddrinfo(res);
|
|
||||||
}
|
}
|
||||||
// make socket non-blocking mode
|
struct addrinfo* rp;
|
||||||
setNonBlockingMode();
|
for(rp = res; rp; rp = rp->ai_next) {
|
||||||
// TODO handle EINTR
|
int fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||||
if(connect(sockfd, (struct sockaddr*)&sockaddr, (socklen_t)sizeof(sockaddr)) == -1 && SOCKET_ERRNO !=
|
if(fd == -1) {
|
||||||
#ifndef __MINGW32__
|
continue;
|
||||||
EINPROGRESS
|
}
|
||||||
#else
|
SOCKOPT_T sockopt = 1;
|
||||||
WSAEWOULDBLOCK
|
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(socklen_t)) < 0) {
|
||||||
#endif // __MINGW32__
|
CLOSE(fd);
|
||||||
) {
|
continue;
|
||||||
throw new DlAbortEx(EX_SOCKET_CONNECT, host.c_str(), errorMsg());
|
}
|
||||||
|
sockfd = fd;
|
||||||
|
// make socket non-blocking mode
|
||||||
|
setNonBlockingMode();
|
||||||
|
if(connect(fd, rp->ai_addr, rp->ai_addrlen) == -1 &&
|
||||||
|
SOCKET_ERRNO != A2_EINPROGRESS) {
|
||||||
|
CLOSE(sockfd);
|
||||||
|
sockfd = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// TODO at this point, connection may not be established and it may fail
|
||||||
|
// later. In such case, next ai_addr should be tried.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
freeaddrinfo(res);
|
||||||
|
if(sockfd == -1) {
|
||||||
|
throw new DlAbortEx(EX_SOCKET_CONNECT, host.c_str(), "all addresses failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,11 +300,7 @@ void SocketCore::closeConnection()
|
||||||
}
|
}
|
||||||
#endif // HAVE_LIBGNUTLS
|
#endif // HAVE_LIBGNUTLS
|
||||||
if(sockfd != -1) {
|
if(sockfd != -1) {
|
||||||
#ifdef __MINGW32__
|
CLOSE(sockfd);
|
||||||
::closesocket(sockfd);
|
|
||||||
#else
|
|
||||||
while(close(sockfd) == -1 && errno == EINTR);
|
|
||||||
#endif // __MINGW32__
|
|
||||||
sockfd = -1;
|
sockfd = -1;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_LIBSSL
|
#ifdef HAVE_LIBSSL
|
||||||
|
@ -578,94 +620,51 @@ void SocketCore::initiateSecureConnection()
|
||||||
#endif // __MINGW32__
|
#endif // __MINGW32__
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
std::string uitos(T value)
|
|
||||||
{
|
|
||||||
std::string str;
|
|
||||||
if(value == 0) {
|
|
||||||
str = "0";
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
int32_t count = 0;
|
|
||||||
while(value) {
|
|
||||||
++count;
|
|
||||||
char digit = value%10+'0';
|
|
||||||
str.insert(str.begin(), digit);
|
|
||||||
value /= 10;
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fillSockaddr(sockaddr* addr, int sockType, const std::string& host, uint16_t port)
|
|
||||||
{
|
|
||||||
struct addrinfo hints;
|
|
||||||
struct addrinfo* result;
|
|
||||||
memset(&hints, 0, sizeof(struct addrinfo));
|
|
||||||
hints.ai_family = AF_INET;
|
|
||||||
hints.ai_socktype = sockType;
|
|
||||||
hints.ai_flags = 0;
|
|
||||||
hints.ai_protocol = 0;
|
|
||||||
{
|
|
||||||
int r = getaddrinfo(host.c_str(), uitos(port).c_str(), &hints, &result);
|
|
||||||
if(r != 0) {
|
|
||||||
throw new DlAbortEx(EX_RESOLVE_HOSTNAME,
|
|
||||||
host.c_str(), gai_strerror(r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memcpy(addr, result->ai_addr, result->ai_addrlen);
|
|
||||||
freeaddrinfo(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SocketCore::writeData(const char* data, size_t len, const std::string& host, uint16_t port)
|
void SocketCore::writeData(const char* data, size_t len, const std::string& host, uint16_t port)
|
||||||
{
|
{
|
||||||
struct sockaddr_storage addrPeer;
|
|
||||||
fillSockaddr((struct sockaddr*)&addrPeer, _sockType, host, port);
|
struct addrinfo hints;
|
||||||
ssize_t r;
|
struct addrinfo* res;
|
||||||
while((r = sendto(sockfd, data, len, 0, (const sockaddr*)&addrPeer, sizeof(struct sockaddr_storage))) == -1 && EINTR == errno);
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = _sockType;
|
||||||
|
hints.ai_flags = 0;
|
||||||
|
hints.ai_protocol = 0;
|
||||||
|
int s;
|
||||||
|
s = getaddrinfo(host.c_str(), uitos(port).c_str(), &hints, &res);
|
||||||
|
if(s) {
|
||||||
|
throw new DlAbortEx(EX_SOCKET_SEND, gai_strerror(s));
|
||||||
|
}
|
||||||
|
struct addrinfo* rp;
|
||||||
|
ssize_t r = -1;
|
||||||
|
for(rp = res; rp; rp = rp->ai_next) {
|
||||||
|
while((r = sendto(sockfd, data, len, 0, rp->ai_addr, rp->ai_addrlen)) == -1 && EINTR == errno);
|
||||||
|
if(r == static_cast<ssize_t>(len)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeaddrinfo(res);
|
||||||
if(r == -1) {
|
if(r == -1) {
|
||||||
throw new DlAbortEx(EX_SOCKET_SEND, errorMsg());
|
throw new DlAbortEx(EX_SOCKET_SEND, errorMsg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t SocketCore::readDataFrom(char* data, size_t len, struct sockaddr* sender, socklen_t* senderLength)
|
|
||||||
{
|
|
||||||
ssize_t r;
|
|
||||||
while((r = recvfrom(sockfd, data, len, 0, sender, senderLength)) == -1 &&
|
|
||||||
EINTR == errno);
|
|
||||||
if(r == -1) {
|
|
||||||
throw new DlAbortEx(EX_SOCKET_RECV, errorMsg());
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t SocketCore::readDataFrom(char* data, size_t len)
|
|
||||||
{
|
|
||||||
|
|
||||||
return readDataFrom(data, len, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t SocketCore::readDataFrom(char* data, size_t len,
|
ssize_t SocketCore::readDataFrom(char* data, size_t len,
|
||||||
std::pair<std::string /* numerichost */,
|
std::pair<std::string /* numerichost */,
|
||||||
uint16_t /* port */>& sender)
|
uint16_t /* port */>& sender)
|
||||||
{
|
{
|
||||||
struct sockaddr_storage addrSender;
|
struct sockaddr_storage sockaddr;
|
||||||
socklen_t addrSenderLength = sizeof(struct sockaddr_storage);
|
socklen_t sockaddrlen = sizeof(struct sockaddr_storage);
|
||||||
ssize_t rlength = readDataFrom(data, len, (struct sockaddr*)&addrSender, &addrSenderLength);
|
struct sockaddr* addrp = reinterpret_cast<struct sockaddr*>(&sockaddr);
|
||||||
|
ssize_t r;
|
||||||
char host[NI_MAXHOST];
|
while((r = recvfrom(sockfd, data, len, 0, addrp, &sockaddrlen)) == -1 &&
|
||||||
char service[NI_MAXSERV];
|
EINTR == errno);
|
||||||
{
|
if(r == -1) {
|
||||||
int s = getnameinfo((struct sockaddr*)&addrSender, addrSenderLength,
|
throw new DlAbortEx(EX_SOCKET_RECV, errorMsg());
|
||||||
host, NI_MAXHOST, service, NI_MAXSERV,
|
|
||||||
NI_NUMERICHOST|NI_NUMERICSERV);
|
|
||||||
if(s != 0) {
|
|
||||||
throw new DlAbortEx("Failed to get peer's hostname and port. cause: %s",
|
|
||||||
gai_strerror(s));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sender.first = host;
|
sender = SocketCore::getNameInfoInNumeric(addrp, sockaddrlen);
|
||||||
sender.second = atoi(service); // TODO
|
|
||||||
return rlength;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -87,6 +87,9 @@ private:
|
||||||
static int error();
|
static int error();
|
||||||
static const char *errorMsg();
|
static const char *errorMsg();
|
||||||
static const char *errorMsg(const int err);
|
static const char *errorMsg(const int err);
|
||||||
|
|
||||||
|
static std::pair<std::string, uint16_t>
|
||||||
|
getNameInfoInNumeric(const struct sockaddr* sockaddr, socklen_t len);
|
||||||
public:
|
public:
|
||||||
SocketCore(int sockType = SOCK_STREAM);
|
SocketCore(int sockType = SOCK_STREAM);
|
||||||
~SocketCore();
|
~SocketCore();
|
||||||
|
@ -206,15 +209,10 @@ public:
|
||||||
readData(reinterpret_cast<char*>(data), len);
|
readData(reinterpret_cast<char*>(data), len);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t readDataFrom(char* data, size_t len, struct sockaddr* sender,
|
|
||||||
socklen_t* senderLength);
|
|
||||||
|
|
||||||
ssize_t readDataFrom(char*, size_t len,
|
ssize_t readDataFrom(char*, size_t len,
|
||||||
std::pair<std::string /* numerichost */,
|
std::pair<std::string /* numerichost */,
|
||||||
uint16_t /* port */>& sender);
|
uint16_t /* port */>& sender);
|
||||||
|
|
||||||
ssize_t readDataFrom(char* data, size_t len);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads up to len bytes from this socket, but bytes are not removed from
|
* Reads up to len bytes from this socket, but bytes are not removed from
|
||||||
* this socket.
|
* this socket.
|
||||||
|
|
|
@ -29,14 +29,13 @@ void DHTConnectionImplTest::testWriteAndReadData()
|
||||||
uint16_t con2port = con2.bind(0);
|
uint16_t con2port = con2.bind(0);
|
||||||
|
|
||||||
std::string message1 = "hello world.";
|
std::string message1 = "hello world.";
|
||||||
con1.sendMessage(message1.c_str(), message1.size(), "localhost", con2port);
|
con1.sendMessage(message1.c_str(), message1.size(), "127.0.0.1", con2port);
|
||||||
|
|
||||||
char readbuffer[100];
|
char readbuffer[100];
|
||||||
std::string remoteHost;
|
std::string remoteHost;
|
||||||
uint16_t remotePort;
|
uint16_t remotePort;
|
||||||
{
|
{
|
||||||
ssize_t rlength = con2.receiveMessage(readbuffer, sizeof(readbuffer), remoteHost, remotePort);
|
ssize_t rlength = con2.receiveMessage(readbuffer, sizeof(readbuffer), remoteHost, remotePort);
|
||||||
CPPUNIT_ASSERT_EQUAL(std::string("127.0.0.1"), remoteHost);
|
|
||||||
CPPUNIT_ASSERT_EQUAL((ssize_t)message1.size(), rlength);
|
CPPUNIT_ASSERT_EQUAL((ssize_t)message1.size(), rlength);
|
||||||
readbuffer[rlength] = '\0';
|
readbuffer[rlength] = '\0';
|
||||||
CPPUNIT_ASSERT_EQUAL(message1, std::string(readbuffer));
|
CPPUNIT_ASSERT_EQUAL(message1, std::string(readbuffer));
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace aria2 {
|
||||||
class PeerMessageUtilTest:public CppUnit::TestFixture {
|
class PeerMessageUtilTest:public CppUnit::TestFixture {
|
||||||
|
|
||||||
CPPUNIT_TEST_SUITE(PeerMessageUtilTest);
|
CPPUNIT_TEST_SUITE(PeerMessageUtilTest);
|
||||||
|
CPPUNIT_TEST(testCreateCompact);
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ public:
|
||||||
void setUp() {
|
void setUp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testCreateCompact();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,4 +39,15 @@ void createNLengthMessage(char* msg, int msgLen, int payloadLen, int id) {
|
||||||
msg[4] = (char)id;
|
msg[4] = (char)id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PeerMessageUtilTest::testCreateCompact()
|
||||||
|
{
|
||||||
|
char compact[6];
|
||||||
|
CPPUNIT_ASSERT(PeerMessageUtil::createcompact(compact, "::ffff:127.0.0.1", 6881));
|
||||||
|
|
||||||
|
std::pair<std::string, uint16_t> p = PeerMessageUtil::unpackcompact(compact);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(std::string("127.0.0.1"), p.first);
|
||||||
|
CPPUNIT_ASSERT_EQUAL((uint16_t)6881, p.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace aria2
|
} // namespace aria2
|
||||||
|
|
|
@ -47,7 +47,7 @@ void SocketCoreTest::testWriteAndReadDatagram()
|
||||||
CPPUNIT_ASSERT_EQUAL(message1, std::string(readbuffer));
|
CPPUNIT_ASSERT_EQUAL(message1, std::string(readbuffer));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
ssize_t rlength = s.readDataFrom(readbuffer, sizeof(readbuffer));
|
ssize_t rlength = s.readDataFrom(readbuffer, sizeof(readbuffer), peer);
|
||||||
CPPUNIT_ASSERT_EQUAL((ssize_t)message2.size(), rlength);
|
CPPUNIT_ASSERT_EQUAL((ssize_t)message2.size(), rlength);
|
||||||
readbuffer[rlength] = '\0';
|
readbuffer[rlength] = '\0';
|
||||||
CPPUNIT_ASSERT_EQUAL(message2, std::string(readbuffer));
|
CPPUNIT_ASSERT_EQUAL(message2, std::string(readbuffer));
|
||||||
|
|
Loading…
Reference in New Issue