1 /*
2 * Copyright (C) 2001-2012 Jacek Sieka, arnetheduck on gmail point com
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include "stdinc.h"
20
21 #include "ConnectivityManager.h"
22 #include "SettingsManager.h"
23 #include "ClientManager.h"
24 #include "ConnectionManager.h"
25 #include "SearchManager.h"
26 #include "LogManager.h"
27 #include "UPnPManager.h"
28 #ifdef WITH_DHT
29 #include "dht/DHT.h"
30 #endif
31
32 namespace dcpp {
33
ConnectivityManager()34 ConnectivityManager::ConnectivityManager() :
35 autoDetected(false),
36 running(false)
37 {
38 updateLast();
39 }
40
startSocket()41 void ConnectivityManager::startSocket() {
42 autoDetected = false;
43
44 disconnect();
45
46 if(ClientManager::getInstance()->isActive()) {
47 listen();
48
49 // must be done after listen calls; otherwise ports won't be set
50 if(SETTING(INCOMING_CONNECTIONS) == SettingsManager::INCOMING_FIREWALL_UPNP)
51 UPnPManager::getInstance()->open();
52 }
53
54 updateLast();
55 }
56
detectConnection()57 void ConnectivityManager::detectConnection() {
58 if (running)
59 return;
60
61 running = true;
62
63 //fire(ConnectivityManagerListener::Started());
64
65 // restore connectivity settings to their default value.
66 SettingsManager::getInstance()->unset(SettingsManager::TCP_PORT);
67 SettingsManager::getInstance()->unset(SettingsManager::UDP_PORT);
68 SettingsManager::getInstance()->unset(SettingsManager::TLS_PORT);
69 SettingsManager::getInstance()->unset(SettingsManager::EXTERNAL_IP);
70 SettingsManager::getInstance()->unset(SettingsManager::NO_IP_OVERRIDE);
71 //SettingsManager::getInstance()->unset(SettingsManager::MAPPER);
72 SettingsManager::getInstance()->unset(SettingsManager::BIND_ADDRESS);
73
74 if (UPnPManager::getInstance()->getOpened()) {
75 UPnPManager::getInstance()->close();
76 }
77
78 disconnect();
79
80 log(_("Determining the best connectivity settings..."));
81 try {
82 listen();
83 } catch(const Exception& e) {
84 SettingsManager::getInstance()->set(SettingsManager::INCOMING_CONNECTIONS, SettingsManager::INCOMING_FIREWALL_PASSIVE);
85 log(str(F_("Unable to open %1% port(s); connectivity settings must be configured manually") % e.getError()));
86 fire(ConnectivityManagerListener::Finished());
87 running = false;
88 return;
89 }
90
91 autoDetected = true;
92
93 if (!Util::isPrivateIp(Util::getLocalIp(AF_INET))) {
94 SettingsManager::getInstance()->set(SettingsManager::INCOMING_CONNECTIONS, SettingsManager::INCOMING_DIRECT);
95 log(_("Public IP address detected, selecting active mode with direct connection"));
96 fire(ConnectivityManagerListener::Finished());
97 running = false;
98 return;
99 }
100
101 SettingsManager::getInstance()->set(SettingsManager::INCOMING_CONNECTIONS, SettingsManager::INCOMING_FIREWALL_UPNP);
102 log(_("Local network with possible NAT detected, trying to map the ports using UPnP..."));
103
104 if (!UPnPManager::getInstance()->open()) {
105 running = false;
106 }
107 }
108
setup(bool settingsChanged)109 void ConnectivityManager::setup(bool settingsChanged) {
110 if(BOOLSETTING(AUTO_DETECT_CONNECTION)) {
111 if (!autoDetected) detectConnection();
112 } else {
113 if(autoDetected || (settingsChanged && (SearchManager::getInstance()->getPort() != SETTING(UDP_PORT) || ConnectionManager::getInstance()->getPort() != SETTING(TCP_PORT) || ConnectionManager::getInstance()->getSecurePort() != SETTING(TLS_PORT) || SETTING(BIND_ADDRESS) != lastBind))) {
114 if(settingsChanged || SETTING(INCOMING_CONNECTIONS) != SettingsManager::INCOMING_FIREWALL_UPNP) {
115 UPnPManager::getInstance()->close();
116 }
117 startSocket();
118 } else if(SETTING(INCOMING_CONNECTIONS) == SettingsManager::INCOMING_FIREWALL_UPNP && !UPnPManager::getInstance()->getOpened()) {
119 // previous UPnP mappings had failed; try again
120 UPnPManager::getInstance()->open();
121 }
122 }
123 }
124
mappingFinished(bool success)125 void ConnectivityManager::mappingFinished(bool success) {
126 if(BOOLSETTING(AUTO_DETECT_CONNECTION)) {
127 if (!success) {
128 disconnect();
129 SettingsManager::getInstance()->set(SettingsManager::INCOMING_CONNECTIONS, SettingsManager::INCOMING_FIREWALL_PASSIVE);
130 log(_("Automatic setup of active mode has failed. You may want to set up your connection manually for better connectivity"));
131 }
132 fire(ConnectivityManagerListener::Finished());
133 }
134
135 running = false;
136 }
137
listen()138 void ConnectivityManager::listen() {
139 try {
140 ConnectionManager::getInstance()->listen();
141 } catch(const Exception&) {
142 throw Exception(_("Transfer (TCP)"));
143 }
144
145 try {
146 SearchManager::getInstance()->listen();
147 } catch(const Exception&) {
148 throw Exception(_("Search (UDP)"));
149 }
150 #ifdef WITH_DHT
151 try {
152 dht::DHT::getInstance()->start();
153 } catch (const Exception&) {
154 throw Exception(_("DHT (UDP)"));
155 }
156 #endif
157 }
158
disconnect()159 void ConnectivityManager::disconnect() {
160 SearchManager::getInstance()->disconnect();
161 ConnectionManager::getInstance()->disconnect();
162 #ifdef WITH_DHT
163 dht::DHT::getInstance()->stop();
164 #endif
165 }
166
log(const string & message)167 void ConnectivityManager::log(const string& message) {
168 if(BOOLSETTING(AUTO_DETECT_CONNECTION)) {
169 LogManager::getInstance()->message(_("Connectivity: ") + message);
170 fire(ConnectivityManagerListener::Message(), message);
171 } else {
172 LogManager::getInstance()->message(message);
173 }
174 }
175
updateLast()176 void ConnectivityManager::updateLast() {
177 lastTcp = (unsigned short)SETTING(TCP_PORT);
178 lastUdp = (unsigned short)SETTING(UDP_PORT);
179 lastTls = (unsigned short)(SETTING(TLS_PORT));
180 lastConn = SETTING(INCOMING_CONNECTIONS);
181 lastBind = SETTING(BIND_ADDRESS);
182 //lastMapper = SETTING(MAPPER);
183 }
184
185 } // namespace dcpp
186