1 /* <!-- copyright */
2 /*
3 * aria2 - The high speed download utility
4 *
5 * Copyright (C) 2006 Tatsuhiro Tsujikawa
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * In addition, as a special exception, the copyright holders give
22 * permission to link the code of portions of this program with the
23 * OpenSSL library under certain conditions as described in each
24 * individual source file, and distribute linked combinations
25 * including the two.
26 * You must obey the GNU General Public License in all respects
27 * for all of the code used other than OpenSSL. If you modify
28 * file(s) with this exception, you may extend this exception to your
29 * version of the file(s), but you are not obligated to do so. If you
30 * do not wish to do so, delete this exception statement from your
31 * version. If you delete this exception statement from all source
32 * files in the program, then also delete it here.
33 */
34 /* copyright --> */
35 #include "InitiateConnectionCommand.h"
36 #include "Request.h"
37 #include "DownloadEngine.h"
38 #include "Option.h"
39 #include "Logger.h"
40 #include "LogFactory.h"
41 #include "message.h"
42 #include "prefs.h"
43 #include "NameResolver.h"
44 #include "SocketCore.h"
45 #include "FileEntry.h"
46 #include "RequestGroup.h"
47 #include "Segment.h"
48 #include "a2functional.h"
49 #include "InitiateConnectionCommandFactory.h"
50 #include "util.h"
51 #include "RecoverableException.h"
52 #include "fmt.h"
53 #include "SocketRecvBuffer.h"
54 #include "BackupIPv4ConnectCommand.h"
55 #include "ConnectCommand.h"
56
57 namespace aria2 {
58
InitiateConnectionCommand(cuid_t cuid,const std::shared_ptr<Request> & req,const std::shared_ptr<FileEntry> & fileEntry,RequestGroup * requestGroup,DownloadEngine * e)59 InitiateConnectionCommand::InitiateConnectionCommand(
60 cuid_t cuid, const std::shared_ptr<Request>& req,
61 const std::shared_ptr<FileEntry>& fileEntry, RequestGroup* requestGroup,
62 DownloadEngine* e)
63 : AbstractCommand(cuid, req, fileEntry, requestGroup, e)
64 {
65 setTimeout(std::chrono::seconds(getOption()->getAsInt(PREF_DNS_TIMEOUT)));
66 // give a chance to be executed in the next loop in DownloadEngine
67 setStatus(Command::STATUS_ONESHOT_REALTIME);
68 disableReadCheckSocket();
69 disableWriteCheckSocket();
70 }
71
72 InitiateConnectionCommand::~InitiateConnectionCommand() = default;
73
executeInternal()74 bool InitiateConnectionCommand::executeInternal()
75 {
76 std::string hostname;
77 uint16_t port;
78 std::shared_ptr<Request> proxyRequest = createProxyRequest();
79 if (!proxyRequest) {
80 hostname = getRequest()->getHost();
81 port = getRequest()->getPort();
82 }
83 else {
84 hostname = proxyRequest->getHost();
85 port = proxyRequest->getPort();
86 }
87 std::vector<std::string> addrs;
88 std::string ipaddr = resolveHostname(addrs, hostname, port);
89 if (ipaddr.empty()) {
90 addCommandSelf();
91 return false;
92 }
93 try {
94 auto c = createNextCommand(hostname, ipaddr, port, addrs, proxyRequest);
95 c->setStatus(Command::STATUS_ONESHOT_REALTIME);
96 getDownloadEngine()->setNoWait(true);
97 getDownloadEngine()->addCommand(std::move(c));
98 return true;
99 }
100 catch (RecoverableException& ex) {
101 // Catch exception and retry another address.
102 // See also AbstractCommand::checkIfConnectionEstablished
103
104 // TODO ipaddr might not be used if pooled socket was found.
105 getDownloadEngine()->markBadIPAddress(hostname, ipaddr, port);
106 if (!getDownloadEngine()->findCachedIPAddress(hostname, port).empty()) {
107 A2_LOG_INFO_EX(EX_EXCEPTION_CAUGHT, ex);
108 A2_LOG_INFO(
109 fmt(MSG_CONNECT_FAILED_AND_RETRY, getCuid(), ipaddr.c_str(), port));
110 auto command =
111 InitiateConnectionCommandFactory::createInitiateConnectionCommand(
112 getCuid(), getRequest(), getFileEntry(), getRequestGroup(),
113 getDownloadEngine());
114 getDownloadEngine()->setNoWait(true);
115 getDownloadEngine()->addCommand(std::move(command));
116 return true;
117 }
118 getDownloadEngine()->removeCachedIPAddress(hostname, port);
119 throw;
120 }
121 }
122
setConnectedAddrInfo(const std::shared_ptr<Request> & req,const std::string & hostname,const std::shared_ptr<SocketCore> & socket)123 void InitiateConnectionCommand::setConnectedAddrInfo(
124 const std::shared_ptr<Request>& req, const std::string& hostname,
125 const std::shared_ptr<SocketCore>& socket)
126 {
127 auto endpoint = socket->getPeerInfo();
128 req->setConnectedAddrInfo(hostname, endpoint.addr, endpoint.port);
129 }
130
131 std::shared_ptr<BackupConnectInfo>
createBackupIPv4ConnectCommand(const std::string & hostname,const std::string & ipaddr,uint16_t port,Command * mainCommand)132 InitiateConnectionCommand::createBackupIPv4ConnectCommand(
133 const std::string& hostname, const std::string& ipaddr, uint16_t port,
134 Command* mainCommand)
135 {
136 // Prepare IPv4 backup connection attempt in "Happy Eyeballs"
137 // fashion.
138 std::shared_ptr<BackupConnectInfo> info;
139 char buf[sizeof(in6_addr)];
140 if (inetPton(AF_INET6, ipaddr.c_str(), &buf) == -1) {
141 return info;
142 }
143 A2_LOG_INFO("Searching IPv4 address for backup connection attempt");
144 std::vector<std::string> addrs;
145 getDownloadEngine()->findAllCachedIPAddresses(std::back_inserter(addrs),
146 hostname, port);
147 for (std::vector<std::string>::const_iterator i = addrs.begin(),
148 eoi = addrs.end();
149 i != eoi; ++i) {
150 if (inetPton(AF_INET, (*i).c_str(), &buf) == 0) {
151 info = std::make_shared<BackupConnectInfo>();
152 auto command = make_unique<BackupIPv4ConnectCommand>(
153 getDownloadEngine()->newCUID(), *i, port, info, mainCommand,
154 getRequestGroup(), getDownloadEngine());
155 A2_LOG_INFO(fmt("Issue backup connection command CUID#%" PRId64
156 ", addr=%s",
157 command->getCuid(), (*i).c_str()));
158 getDownloadEngine()->addCommand(std::move(command));
159 return info;
160 }
161 }
162 return info;
163 }
164
setupBackupConnection(const std::string & hostname,const std::string & addr,uint16_t port,ConnectCommand * c)165 void InitiateConnectionCommand::setupBackupConnection(
166 const std::string& hostname, const std::string& addr, uint16_t port,
167 ConnectCommand* c)
168 {
169 std::shared_ptr<BackupConnectInfo> backupConnectInfo =
170 createBackupIPv4ConnectCommand(hostname, addr, port, c);
171 if (backupConnectInfo) {
172 c->setBackupConnectInfo(backupConnectInfo);
173 }
174 }
175
176 } // namespace aria2
177