|
@@ -50,9 +50,12 @@
|
|
|
#include "Socket.h"
|
|
|
#include "Util.h"
|
|
|
#include "a2functional.h"
|
|
|
+#include "DlAbortEx.h"
|
|
|
#include <signal.h>
|
|
|
#include <cstring>
|
|
|
#include <algorithm>
|
|
|
+#include <numeric>
|
|
|
+#include <cerrno>
|
|
|
|
|
|
namespace aria2 {
|
|
|
|
|
@@ -63,40 +66,361 @@ namespace aria2 {
|
|
|
// 4 ... 2nd stop signal processed by DownloadEngine
|
|
|
volatile sig_atomic_t globalHaltRequested = 0;
|
|
|
|
|
|
-SocketEntry::SocketEntry(const SocketHandle& socket,
|
|
|
- Command* command,
|
|
|
- TYPE type):
|
|
|
- socket(socket), command(command), type(type) {}
|
|
|
|
|
|
-bool SocketEntry::operator==(const SocketEntry& entry)
|
|
|
+CommandEvent::CommandEvent(Command* command, int events):
|
|
|
+ _command(command), _events(events) {}
|
|
|
+
|
|
|
+bool CommandEvent::operator==(const CommandEvent& commandEvent) const
|
|
|
+{
|
|
|
+ return _command == commandEvent._command;
|
|
|
+}
|
|
|
+
|
|
|
+int CommandEvent::getEvents() const
|
|
|
+{
|
|
|
+ return _events;
|
|
|
+}
|
|
|
+
|
|
|
+void CommandEvent::addEvents(int events)
|
|
|
+{
|
|
|
+ _events |= events;
|
|
|
+}
|
|
|
+
|
|
|
+void CommandEvent::removeEvents(int events)
|
|
|
+{
|
|
|
+ _events &= (~events);
|
|
|
+}
|
|
|
+
|
|
|
+bool CommandEvent::eventsEmpty() const
|
|
|
+{
|
|
|
+ return _events == 0;
|
|
|
+}
|
|
|
+
|
|
|
+void CommandEvent::processEvents(int events)
|
|
|
+{
|
|
|
+ if((_events&events) ||
|
|
|
+ ((SocketEntry::EVENT_ERROR|SocketEntry::EVENT_HUP)&events)) {
|
|
|
+ _command->setStatusActive();
|
|
|
+ }
|
|
|
+ if(SocketEntry::EVENT_READ&events) {
|
|
|
+ _command->readEventReceived();
|
|
|
+ }
|
|
|
+ if(SocketEntry::EVENT_WRITE&events) {
|
|
|
+ _command->writeEventReceived();
|
|
|
+ }
|
|
|
+ if((SocketEntry::EVENT_ERROR|SocketEntry::EVENT_HUP)&events) {
|
|
|
+ _command->errorEventRecieved();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#if defined HAVE_EPOLL && defined ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ADNSEvent::ADNSEvent(const SharedHandle<AsyncNameResolver>& resolver,
|
|
|
+ Command* command,
|
|
|
+ int socket, int events):
|
|
|
+ _resolver(resolver), _command(command), _socket(socket), _events(events) {}
|
|
|
+
|
|
|
+bool ADNSEvent::operator==(const ADNSEvent& event) const
|
|
|
{
|
|
|
- return socket == entry.socket &&
|
|
|
- command == entry.command &&
|
|
|
- type == entry.type;
|
|
|
+ return _resolver == event._resolver;
|
|
|
}
|
|
|
|
|
|
+int ADNSEvent::getEvents() const
|
|
|
+{
|
|
|
+ return _events;
|
|
|
+}
|
|
|
+
|
|
|
+void ADNSEvent::processEvents(int events)
|
|
|
+{
|
|
|
+ ares_socket_t readfd;
|
|
|
+ ares_socket_t writefd;
|
|
|
+ if(events&EPOLLIN) {
|
|
|
+ readfd = _socket;
|
|
|
+ } else {
|
|
|
+ readfd = ARES_SOCKET_BAD;
|
|
|
+ }
|
|
|
+ if(events&EPOLLOUT) {
|
|
|
+ writefd = _socket;
|
|
|
+ } else {
|
|
|
+ writefd = ARES_SOCKET_BAD;
|
|
|
+ }
|
|
|
+ _resolver->process(readfd, writefd);
|
|
|
+ _command->setStatusActive();
|
|
|
+}
|
|
|
+
|
|
|
+#endif // HAVE_EPOLL && ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+SocketEntry::SocketEntry(int socket):_socket(socket)
|
|
|
+{
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+ memset(&_epEvent, 0, sizeof(struct epoll_event));
|
|
|
+#endif // HAVE_EPOLL
|
|
|
+}
|
|
|
+
|
|
|
+bool SocketEntry::operator==(const SocketEntry& entry) const
|
|
|
+{
|
|
|
+ return _socket == entry._socket;
|
|
|
+}
|
|
|
+
|
|
|
+bool SocketEntry::operator<(const SocketEntry& entry) const
|
|
|
+{
|
|
|
+ return _socket < entry._socket;
|
|
|
+}
|
|
|
+
|
|
|
+void SocketEntry::addCommandEvent(Command* command, int events)
|
|
|
+{
|
|
|
+ CommandEvent cev(command, events);
|
|
|
+ std::deque<CommandEvent>::iterator i = std::find(_commandEvents.begin(),
|
|
|
+ _commandEvents.end(),
|
|
|
+ cev);
|
|
|
+ if(i == _commandEvents.end()) {
|
|
|
+ _commandEvents.push_back(cev);
|
|
|
+ } else {
|
|
|
+ (*i).addEvents(events);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void SocketEntry::removeCommandEvent(Command* command, int events)
|
|
|
+{
|
|
|
+ CommandEvent cev(command, events);
|
|
|
+ std::deque<CommandEvent>::iterator i = std::find(_commandEvents.begin(),
|
|
|
+ _commandEvents.end(),
|
|
|
+ cev);
|
|
|
+ if(i == _commandEvents.end()) {
|
|
|
+ // not found
|
|
|
+ } else {
|
|
|
+ (*i).removeEvents(events);
|
|
|
+ if((*i).eventsEmpty()) {
|
|
|
+ _commandEvents.erase(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#if defined HAVE_EPOLL && defined ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+void SocketEntry::addADNSEvent(const SharedHandle<AsyncNameResolver>& resolver,
|
|
|
+ Command* command, int events)
|
|
|
+{
|
|
|
+ ADNSEvent aev(resolver, command, _socket, events);
|
|
|
+ std::deque<ADNSEvent>::iterator i = std::find(_adnsEvents.begin(),
|
|
|
+ _adnsEvents.end(),
|
|
|
+ aev);
|
|
|
+ if(i == _adnsEvents.end()) {
|
|
|
+ _adnsEvents.push_back(aev);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void SocketEntry::removeADNSEvent(const SharedHandle<AsyncNameResolver>& resolver,
|
|
|
+ Command* command)
|
|
|
+{
|
|
|
+ ADNSEvent aev(resolver, command, _socket, 0);
|
|
|
+ std::deque<ADNSEvent>::iterator i = std::find(_adnsEvents.begin(),
|
|
|
+ _adnsEvents.end(),
|
|
|
+ aev);
|
|
|
+ if(i == _adnsEvents.end()) {
|
|
|
+ // not found
|
|
|
+ } else {
|
|
|
+ _adnsEvents.erase(i);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#endif // HAVE_EPOLL && ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+void SocketEntry::processEvents(int events)
|
|
|
+{
|
|
|
+ std::for_each(_commandEvents.begin(), _commandEvents.end(),
|
|
|
+ std::bind2nd(std::mem_fun_ref(&CommandEvent::processEvents),
|
|
|
+ events));
|
|
|
+
|
|
|
+#if defined HAVE_EPOLL && defined ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ std::for_each(_adnsEvents.begin(), _adnsEvents.end(),
|
|
|
+ std::bind2nd(std::mem_fun_ref(&ADNSEvent::processEvents),
|
|
|
+ events));
|
|
|
+
|
|
|
+#endif // HAVE_EPOLL && ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+int SocketEntry::getSocket() const
|
|
|
+{
|
|
|
+ return _socket;
|
|
|
+}
|
|
|
+
|
|
|
+bool SocketEntry::eventEmpty() const
|
|
|
+{
|
|
|
+
|
|
|
+#if defined HAVE_EPOLL && defined ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ return _commandEvents.empty() && _adnsEvents.empty();
|
|
|
+
|
|
|
+#else // !(HAVE_EPOLL && ENABLE_ASYNC_DNS)
|
|
|
+
|
|
|
+ return _commandEvents.empty();
|
|
|
+
|
|
|
+#endif // !(HAVE_EPOLL && ENABLE_ASYNC_DNS)
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+class AccEvent {
|
|
|
+public:
|
|
|
+ int operator()(int events, const CommandEvent& commandEvent) const
|
|
|
+ {
|
|
|
+ return events|commandEvent.getEvents();
|
|
|
+ }
|
|
|
+
|
|
|
+#if defined HAVE_EPOLL && defined ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ int operator()(int events, const ADNSEvent& adnsEvent) const
|
|
|
+ {
|
|
|
+ return events|adnsEvent.getEvents();
|
|
|
+ }
|
|
|
+
|
|
|
+#endif // HAVE_EPOLL && ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+
|
|
|
+struct epoll_event& SocketEntry::getEpEvent()
|
|
|
+{
|
|
|
+ _epEvent.data.ptr = this;
|
|
|
+
|
|
|
+#ifdef ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ _epEvent.events =
|
|
|
+ std::accumulate(_adnsEvents.begin(),
|
|
|
+ _adnsEvents.end(),
|
|
|
+ std::accumulate(_commandEvents.begin(),
|
|
|
+ _commandEvents.end(), 0, AccEvent()),
|
|
|
+ AccEvent());
|
|
|
+
|
|
|
+#else // !ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ _epEvent.events =
|
|
|
+ std::accumulate(_commandEvents.begin(), _commandEvents.end(), 0, AccEvent());
|
|
|
+
|
|
|
+#endif // !ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ return _epEvent;
|
|
|
+}
|
|
|
+
|
|
|
+#else // !HAVE_EPOLL
|
|
|
+
|
|
|
+int SocketEntry::getEvents()
|
|
|
+{
|
|
|
+ return
|
|
|
+ std::accumulate(_commandEvents.begin(), _commandEvents.end(), 0, AccEvent());
|
|
|
+}
|
|
|
+
|
|
|
+#endif // !HAVE_EPOLL
|
|
|
+
|
|
|
+
|
|
|
#ifdef ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
AsyncNameResolverEntry::AsyncNameResolverEntry
|
|
|
-(const SharedHandle<AsyncNameResolver>& nameResolver,
|
|
|
- Command* command):
|
|
|
- nameResolver(nameResolver), command(command) {}
|
|
|
+(const SharedHandle<AsyncNameResolver>& nameResolver, Command* command):
|
|
|
+ _nameResolver(nameResolver), _command(command)
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+ , _socketsSize(0)
|
|
|
+#endif // HAVE_EPOLL
|
|
|
+{}
|
|
|
|
|
|
bool AsyncNameResolverEntry::operator==(const AsyncNameResolverEntry& entry)
|
|
|
{
|
|
|
- return nameResolver == entry.nameResolver &&
|
|
|
- command == entry.command;
|
|
|
+ return _nameResolver == entry._nameResolver &&
|
|
|
+ _command == entry._command;
|
|
|
}
|
|
|
+
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+
|
|
|
+void AsyncNameResolverEntry::addSocketEvents(DownloadEngine* e)
|
|
|
+{
|
|
|
+ _socketsSize = 0;
|
|
|
+ int mask = _nameResolver->getsock(_sockets);
|
|
|
+ if(mask == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ size_t i;
|
|
|
+ for(i = 0; i < ARES_GETSOCK_MAXNUM; ++i) {
|
|
|
+ //epoll_event_t* epEventPtr = &_epEvents[_socketsSize];
|
|
|
+ int events = 0;
|
|
|
+ if(ARES_GETSOCK_READABLE(mask, i)) {
|
|
|
+ events |= EPOLLIN;
|
|
|
+ }
|
|
|
+ if(ARES_GETSOCK_WRITABLE(mask, i)) {
|
|
|
+ events |= EPOLLOUT;
|
|
|
+ }
|
|
|
+ if(events == 0) {
|
|
|
+ // assume no further sockets are returned.
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ e->addSocketEvents(_sockets[i], _command, events, _nameResolver);
|
|
|
+ }
|
|
|
+ _socketsSize = i;
|
|
|
+}
|
|
|
+
|
|
|
+void AsyncNameResolverEntry::removeSocketEvents(DownloadEngine* e)
|
|
|
+{
|
|
|
+ for(size_t i = 0; i < _socketsSize; ++i) {
|
|
|
+ e->deleteSocketEvents(_sockets[i], _command, 0, _nameResolver);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#else // !HAVE_EPOLL
|
|
|
+
|
|
|
+int AsyncNameResolverEntry::getFds(fd_set* rfdsPtr, fd_set* wfdsPtr)
|
|
|
+{
|
|
|
+ return _nameResolver->getFds(rfdsPtr, wfdsPtr);
|
|
|
+}
|
|
|
+
|
|
|
+void AsyncNameResolverEntry::process(fd_set* rfdsPtr, fd_set* wfdsPtr)
|
|
|
+{
|
|
|
+ _nameResolver->process(rfdsPtr, wfdsPtr);
|
|
|
+ switch(_nameResolver->getStatus()) {
|
|
|
+ case AsyncNameResolver::STATUS_SUCCESS:
|
|
|
+ case AsyncNameResolver::STATUS_ERROR:
|
|
|
+ _command->setStatusActive();
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#endif // !HAVE_EPOLL
|
|
|
+
|
|
|
#endif // ENABLE_ASYNC_DNS
|
|
|
|
|
|
DownloadEngine::DownloadEngine():logger(LogFactory::getInstance()),
|
|
|
_haltRequested(false),
|
|
|
_noWait(false)
|
|
|
{
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+
|
|
|
+ _epfd = epoll_create(EPOLL_EVENTS_MAX);
|
|
|
+
|
|
|
+#else // !HAVE_EPOLL
|
|
|
+
|
|
|
updateFdSet();
|
|
|
+
|
|
|
+#endif // !HAVE_EPOLL
|
|
|
}
|
|
|
|
|
|
DownloadEngine::~DownloadEngine() {
|
|
|
cleanQueue();
|
|
|
+
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+
|
|
|
+ if(_epfd != -1) {
|
|
|
+ int r;
|
|
|
+ while((r = close(_epfd)) == -1 && errno == EINTR);
|
|
|
+ if(r == -1) {
|
|
|
+ logger->error("Error occurred while closing epoll file descriptor %d: %s",
|
|
|
+ _epfd, strerror(errno));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+#endif // HAVE_EPOLL
|
|
|
}
|
|
|
|
|
|
void DownloadEngine::cleanQueue() {
|
|
@@ -115,14 +439,27 @@ static void executeCommand(std::deque<Command*>& commands,
|
|
|
com->transitStatus();
|
|
|
if(com->execute()) {
|
|
|
delete com;
|
|
|
+ com = 0;
|
|
|
}
|
|
|
} else {
|
|
|
commands.push_back(com);
|
|
|
}
|
|
|
+ if(com) {
|
|
|
+ com->clearIOEvents();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void DownloadEngine::run() {
|
|
|
+
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+
|
|
|
+ if(_epfd == -1) {
|
|
|
+ throw DlAbortEx("epoll_init() failed.");
|
|
|
+ }
|
|
|
+
|
|
|
+#endif // HAVE_EPOLL
|
|
|
+
|
|
|
Time cp;
|
|
|
cp.setTimeInSec(0);
|
|
|
while(!commands.empty() || !_routineCommands.empty()) {
|
|
@@ -152,7 +489,33 @@ void DownloadEngine::shortSleep() const {
|
|
|
select(0, &rfds, NULL, NULL, &tv);
|
|
|
}
|
|
|
|
|
|
-void DownloadEngine::waitData() {
|
|
|
+void DownloadEngine::waitData()
|
|
|
+{
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+
|
|
|
+ // timeout is millisec
|
|
|
+ int timeout = _noWait ? 0 : 1000;
|
|
|
+
|
|
|
+ // TODO make member variable
|
|
|
+ const size_t _maxEpEvents = EPOLL_EVENTS_MAX;
|
|
|
+ struct epoll_event _epEvents[_maxEpEvents];
|
|
|
+
|
|
|
+ int res;
|
|
|
+ while((res = epoll_wait(_epfd, _epEvents, _maxEpEvents, timeout)) == -1 &&
|
|
|
+ errno == EINTR);
|
|
|
+
|
|
|
+ if(res > 0) {
|
|
|
+ for(int i = 0; i < res; ++i) {
|
|
|
+ SocketEntry* p = (SocketEntry*)_epEvents[i].data.ptr;
|
|
|
+ p->processEvents(_epEvents[i].events);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // TODO timeout of name resolver is determined in Command(AbstractCommand,
|
|
|
+ // DHTEntryPoint...Command)
|
|
|
+
|
|
|
+#else // !HAVE_EPOLL
|
|
|
+
|
|
|
fd_set rfds;
|
|
|
fd_set wfds;
|
|
|
struct timeval tv;
|
|
@@ -161,62 +524,63 @@ void DownloadEngine::waitData() {
|
|
|
memcpy(&wfds, &wfdset, sizeof(fd_set));
|
|
|
|
|
|
#ifdef ENABLE_ASYNC_DNS
|
|
|
- for(AsyncNameResolverEntries::iterator itr = nameResolverEntries.begin();
|
|
|
- itr != nameResolverEntries.end(); ++itr) {
|
|
|
- AsyncNameResolverEntry& entry = *itr;
|
|
|
- int fd = entry.nameResolver->getFds(&rfds, &wfds);
|
|
|
+
|
|
|
+ for(std::deque<SharedHandle<AsyncNameResolverEntry> >::iterator itr =
|
|
|
+ nameResolverEntries.begin(); itr != nameResolverEntries.end(); ++itr) {
|
|
|
+ SharedHandle<AsyncNameResolverEntry>& entry = *itr;
|
|
|
+ int fd = entry->getFds(&rfds, &wfds);
|
|
|
// TODO force error if fd == 0
|
|
|
if(fdmax < fd) {
|
|
|
fdmax = fd;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
#endif // ENABLE_ASYNC_DNS
|
|
|
|
|
|
tv.tv_sec = _noWait ? 0 : 1;
|
|
|
tv.tv_usec = 0;
|
|
|
int retval = select(fdmax+1, &rfds, &wfds, NULL, &tv);
|
|
|
if(retval > 0) {
|
|
|
- for(SocketEntries::iterator itr = socketEntries.begin();
|
|
|
- itr != socketEntries.end(); ++itr) {
|
|
|
- SocketEntry& entry = *itr;
|
|
|
- if(FD_ISSET(entry.socket->getSockfd(), &rfds) ||
|
|
|
- FD_ISSET(entry.socket->getSockfd(), &wfds)) {
|
|
|
- entry.command->setStatusActive();
|
|
|
+ for(std::deque<SharedHandle<SocketEntry> >::iterator i =
|
|
|
+ socketEntries.begin(); i != socketEntries.end(); ++i) {
|
|
|
+ int events = 0;
|
|
|
+ if(FD_ISSET((*i)->getSocket(), &rfds)) {
|
|
|
+ events |= SocketEntry::EVENT_READ;
|
|
|
}
|
|
|
+ if(FD_ISSET((*i)->getSocket(), &wfds)) {
|
|
|
+ events |= SocketEntry::EVENT_WRITE;
|
|
|
+ }
|
|
|
+ (*i)->processEvents(events);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
#ifdef ENABLE_ASYNC_DNS
|
|
|
- for(AsyncNameResolverEntries::iterator itr = nameResolverEntries.begin();
|
|
|
- itr != nameResolverEntries.end(); ++itr) {
|
|
|
- AsyncNameResolverEntry& entry = *itr;
|
|
|
- entry.nameResolver->process(&rfds, &wfds);
|
|
|
- switch(entry.nameResolver->getStatus()) {
|
|
|
- case AsyncNameResolver::STATUS_SUCCESS:
|
|
|
- case AsyncNameResolver::STATUS_ERROR:
|
|
|
- entry.command->setStatusActive();
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
+
|
|
|
+ for(std::deque<SharedHandle<AsyncNameResolverEntry> >::iterator i =
|
|
|
+ nameResolverEntries.begin(); i != nameResolverEntries.end(); ++i) {
|
|
|
+ (*i)->process(&rfds, &wfds);
|
|
|
}
|
|
|
+
|
|
|
#endif // ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+#endif // !HAVE_EPOLL
|
|
|
}
|
|
|
|
|
|
+#ifndef HAVE_EPOLL
|
|
|
+
|
|
|
void DownloadEngine::updateFdSet() {
|
|
|
fdmax = 0;
|
|
|
FD_ZERO(&rfdset);
|
|
|
FD_ZERO(&wfdset);
|
|
|
- for(SocketEntries::iterator itr = socketEntries.begin();
|
|
|
- itr != socketEntries.end(); ++itr) {
|
|
|
- SocketEntry& entry = *itr;
|
|
|
- int fd = entry.socket->getSockfd();
|
|
|
- switch(entry.type) {
|
|
|
- case SocketEntry::TYPE_RD:
|
|
|
+ for(std::deque<SharedHandle<SocketEntry> >::iterator i =
|
|
|
+ socketEntries.begin(); i != socketEntries.end(); ++i) {
|
|
|
+ int fd = (*i)->getSocket();
|
|
|
+ int events = (*i)->getEvents();
|
|
|
+ if(events&SocketEntry::EVENT_READ) {
|
|
|
FD_SET(fd, &rfdset);
|
|
|
- break;
|
|
|
- case SocketEntry::TYPE_WR:
|
|
|
+ }
|
|
|
+ if(events&SocketEntry::EVENT_WRITE) {
|
|
|
FD_SET(fd, &wfdset);
|
|
|
- break;
|
|
|
}
|
|
|
if(fdmax < fd) {
|
|
|
fdmax = fd;
|
|
@@ -224,52 +588,191 @@ void DownloadEngine::updateFdSet() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-bool DownloadEngine::addSocket(const SocketEntry& entry) {
|
|
|
- SocketEntries::iterator itr =
|
|
|
- std::find(socketEntries.begin(), socketEntries.end(), entry);
|
|
|
- if(itr == socketEntries.end()) {
|
|
|
- socketEntries.push_back(entry);
|
|
|
- updateFdSet();
|
|
|
- return true;
|
|
|
+#endif // !HAVE_EPOLL
|
|
|
+
|
|
|
+bool DownloadEngine::addSocketEvents(int socket, Command* command, int events
|
|
|
+#if defined HAVE_EPOLL && defined ENABLE_ASYNC_DNS
|
|
|
+ ,const SharedHandle<AsyncNameResolver>& rs
|
|
|
+#endif // HAVE_EPOLL && ENABLE_ASYNC_DNS
|
|
|
+ )
|
|
|
+{
|
|
|
+ SharedHandle<SocketEntry> socketEntry(new SocketEntry(socket));
|
|
|
+ std::deque<SharedHandle<SocketEntry> >::iterator i =
|
|
|
+ std::lower_bound(socketEntries.begin(), socketEntries.end(), socketEntry);
|
|
|
+ int r = 0;
|
|
|
+ if(i != socketEntries.end() && (*i) == socketEntry) {
|
|
|
+
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+
|
|
|
+#ifdef ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ if(rs.isNull()) {
|
|
|
+ (*i)->addCommandEvent(command, events);
|
|
|
+ } else {
|
|
|
+ (*i)->addADNSEvent(rs, command, events);
|
|
|
+ }
|
|
|
+
|
|
|
+#else // !ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ (*i)->addCommandEvent(command, events);
|
|
|
+
|
|
|
+#endif // !ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ r = epoll_ctl(_epfd, EPOLL_CTL_MOD, (*i)->getSocket(), &(*i)->getEpEvent());
|
|
|
+ if(r == -1) {
|
|
|
+ // try EPOLL_CTL_ADD: There is a chance that previously socket X is
|
|
|
+ // added to epoll, but it is closed and is not yet removed from
|
|
|
+ // SocketEntries. In this case, EPOLL_CTL_MOD is failed with ENOENT.
|
|
|
+
|
|
|
+ r = epoll_ctl(_epfd, EPOLL_CTL_ADD, (*i)->getSocket(), &(*i)->getEpEvent());
|
|
|
+ }
|
|
|
+
|
|
|
+#else // !HAVE_EPOLL
|
|
|
+
|
|
|
+ (*i)->addCommandEvent(command, events);
|
|
|
+
|
|
|
+#endif // !HAVE_EPOLL
|
|
|
+
|
|
|
} else {
|
|
|
- return false;
|
|
|
+ socketEntries.insert(i, socketEntry);
|
|
|
+
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+
|
|
|
+#ifdef ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ if(rs.isNull()) {
|
|
|
+ socketEntry->addCommandEvent(command, events);
|
|
|
+ } else {
|
|
|
+ socketEntry->addADNSEvent(rs, command, events);
|
|
|
+ }
|
|
|
+
|
|
|
+#else // !ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ socketEntry->addCommandEvent(command, events);
|
|
|
+
|
|
|
+#endif // !ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ r = epoll_ctl(_epfd, EPOLL_CTL_ADD, socketEntry->getSocket(), &socketEntry->getEpEvent());
|
|
|
+
|
|
|
+#else // !HAVE_EPOLL
|
|
|
+
|
|
|
+ socketEntry->addCommandEvent(command, events);
|
|
|
+
|
|
|
+#endif // !HAVE_EPOLL
|
|
|
+
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-bool DownloadEngine::deleteSocket(const SocketEntry& entry) {
|
|
|
- SocketEntries::iterator itr =
|
|
|
- std::find(socketEntries.begin(), socketEntries.end(), entry);
|
|
|
- if(itr == socketEntries.end()) {
|
|
|
+#ifndef HAVE_EPOLL
|
|
|
+
|
|
|
+ updateFdSet();
|
|
|
+
|
|
|
+#endif // !HAVE_EPOLL
|
|
|
+
|
|
|
+ if(r == -1) {
|
|
|
+ logger->debug("Failed to add socket event %d:%s", socket, strerror(errno));
|
|
|
return false;
|
|
|
} else {
|
|
|
- socketEntries.erase(itr);
|
|
|
- updateFdSet();
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+bool DownloadEngine::deleteSocketEvents(int socket, Command* command, int events
|
|
|
+#if defined HAVE_EPOLL && defined ENABLE_ASYNC_DNS
|
|
|
+ ,const SharedHandle<AsyncNameResolver>& rs
|
|
|
+#endif // HAVE_EPOLL && ENABLE_ASYNC_DNS
|
|
|
+ )
|
|
|
+{
|
|
|
+ SharedHandle<SocketEntry> socketEntry(new SocketEntry(socket));
|
|
|
+ std::deque<SharedHandle<SocketEntry> >::iterator i =
|
|
|
+ std::lower_bound(socketEntries.begin(), socketEntries.end(), socketEntry);
|
|
|
+ if(i != socketEntries.end() && (*i) == socketEntry) {
|
|
|
+
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+
|
|
|
+#ifdef ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ if(rs.isNull()) {
|
|
|
+ (*i)->removeCommandEvent(command, events);
|
|
|
+ } else {
|
|
|
+ (*i)->removeADNSEvent(rs, command);
|
|
|
+ }
|
|
|
+
|
|
|
+#else // !ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+ (*i)->removeCommandEvent(command, events);
|
|
|
+
|
|
|
+#endif // !ENABLE_ASYNC_DNS
|
|
|
+
|
|
|
+#else // !HAVE_EPOLL
|
|
|
+
|
|
|
+ (*i)->removeCommandEvent(command, events);
|
|
|
+
|
|
|
+#endif // !HAVE_EPOLL
|
|
|
+
|
|
|
+ int r = 0;
|
|
|
+ if((*i)->eventEmpty()) {
|
|
|
+
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+
|
|
|
+ r = epoll_ctl(_epfd, EPOLL_CTL_DEL, (*i)->getSocket(), 0);
|
|
|
+
|
|
|
+#endif // HAVE_EPOLL
|
|
|
+
|
|
|
+ socketEntries.erase(i);
|
|
|
+ } else {
|
|
|
+
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+
|
|
|
+ // If socket is closed, then it seems it is automatically removed from
|
|
|
+ // epoll, so following EPOLL_CTL_MOD may fail.
|
|
|
+ r = epoll_ctl(_epfd, EPOLL_CTL_MOD, (*i)->getSocket(), &(*i)->getEpEvent());
|
|
|
+ if(r == -1) {
|
|
|
+ logger->debug("Failed to delete socket event, but may be ignored:%s", strerror(errno));
|
|
|
+ }
|
|
|
+#endif // HAVE_EPOLL
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+#ifndef HAVE_EPOLL
|
|
|
+
|
|
|
+ updateFdSet();
|
|
|
+
|
|
|
+#endif // !HAVE_EPOLL
|
|
|
+
|
|
|
+ if(r == -1) {
|
|
|
+ logger->debug("Failed to delete socket event:%s", strerror(errno));
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ logger->debug("Socket %d is not found in SocketEntries.", socket);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
bool DownloadEngine::addSocketForReadCheck(const SocketHandle& socket,
|
|
|
- Command* command) {
|
|
|
- SocketEntry entry(socket, command, SocketEntry::TYPE_RD);
|
|
|
- return addSocket(entry);
|
|
|
+ Command* command)
|
|
|
+{
|
|
|
+ return addSocketEvents(socket->getSockfd(), command, SocketEntry::EVENT_READ);
|
|
|
}
|
|
|
|
|
|
bool DownloadEngine::deleteSocketForReadCheck(const SocketHandle& socket,
|
|
|
- Command* command) {
|
|
|
- SocketEntry entry(socket, command, SocketEntry::TYPE_RD);
|
|
|
- return deleteSocket(entry);
|
|
|
+ Command* command)
|
|
|
+{
|
|
|
+ return deleteSocketEvents(socket->getSockfd(), command, SocketEntry::EVENT_READ);
|
|
|
}
|
|
|
|
|
|
bool DownloadEngine::addSocketForWriteCheck(const SocketHandle& socket,
|
|
|
- Command* command) {
|
|
|
- SocketEntry entry(socket, command, SocketEntry::TYPE_WR);
|
|
|
- return addSocket(entry);
|
|
|
+ Command* command)
|
|
|
+{
|
|
|
+ return addSocketEvents(socket->getSockfd(), command, SocketEntry::EVENT_WRITE);
|
|
|
}
|
|
|
|
|
|
bool DownloadEngine::deleteSocketForWriteCheck(const SocketHandle& socket,
|
|
|
- Command* command) {
|
|
|
- SocketEntry entry(socket, command, SocketEntry::TYPE_WR);
|
|
|
- return deleteSocket(entry);
|
|
|
+ Command* command)
|
|
|
+{
|
|
|
+ return deleteSocketEvents(socket->getSockfd(), command, SocketEntry::EVENT_WRITE);
|
|
|
}
|
|
|
|
|
|
void DownloadEngine::calculateStatistics()
|
|
@@ -323,14 +826,21 @@ void DownloadEngine::addCommand(const Commands& commands)
|
|
|
|
|
|
#ifdef ENABLE_ASYNC_DNS
|
|
|
bool DownloadEngine::addNameResolverCheck
|
|
|
-(const SharedHandle<AsyncNameResolver>& resolver,
|
|
|
- Command* command)
|
|
|
+(const SharedHandle<AsyncNameResolver>& resolver, Command* command)
|
|
|
{
|
|
|
- AsyncNameResolverEntry entry(resolver, command);
|
|
|
- AsyncNameResolverEntries::iterator itr =
|
|
|
+ SharedHandle<AsyncNameResolverEntry> entry
|
|
|
+ (new AsyncNameResolverEntry(resolver, command));
|
|
|
+ std::deque<SharedHandle<AsyncNameResolverEntry> >::iterator itr =
|
|
|
std::find(nameResolverEntries.begin(), nameResolverEntries.end(), entry);
|
|
|
if(itr == nameResolverEntries.end()) {
|
|
|
nameResolverEntries.push_back(entry);
|
|
|
+
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+
|
|
|
+ entry->addSocketEvents(this);
|
|
|
+
|
|
|
+#endif // HAVE_EPOLL
|
|
|
+
|
|
|
return true;
|
|
|
} else {
|
|
|
return false;
|
|
@@ -338,15 +848,22 @@ bool DownloadEngine::addNameResolverCheck
|
|
|
}
|
|
|
|
|
|
bool DownloadEngine::deleteNameResolverCheck
|
|
|
-(const SharedHandle<AsyncNameResolver>& resolver,
|
|
|
- Command* command)
|
|
|
+(const SharedHandle<AsyncNameResolver>& resolver, Command* command)
|
|
|
{
|
|
|
- AsyncNameResolverEntry entry(resolver, command);
|
|
|
- AsyncNameResolverEntries::iterator itr =
|
|
|
+ SharedHandle<AsyncNameResolverEntry> entry
|
|
|
+ (new AsyncNameResolverEntry(resolver, command));
|
|
|
+ std::deque<SharedHandle<AsyncNameResolverEntry> >::iterator itr =
|
|
|
std::find(nameResolverEntries.begin(), nameResolverEntries.end(), entry);
|
|
|
if(itr == nameResolverEntries.end()) {
|
|
|
return false;
|
|
|
} else {
|
|
|
+
|
|
|
+#ifdef HAVE_EPOLL
|
|
|
+
|
|
|
+ (*itr)->removeSocketEvents(this);
|
|
|
+
|
|
|
+#endif // HAVE_EPOLL
|
|
|
+
|
|
|
nameResolverEntries.erase(itr);
|
|
|
return true;
|
|
|
}
|