Status: | Needs review |
---|---|
Proposed branch: | lp:~maksis/adchpp/adchpp-hbri |
Merge into: | lp:adchpp |
Diff against target: |
1149 lines (+457/-101) 19 files modified
adchpp/AdcCommand.cpp (+1/-1) adchpp/AdcCommand.h (+5/-1) adchpp/Client.h (+2/-0) adchpp/ClientManager.cpp (+229/-55) adchpp/ClientManager.h (+12/-2) adchpp/Entity.cpp (+37/-3) adchpp/Entity.h (+12/-1) adchpp/ManagedSocket.cpp (+38/-2) adchpp/ManagedSocket.h (+7/-1) adchpp/ServerInfo.h (+4/-1) adchpp/SocketManager.cpp (+65/-26) adchpp/SocketManager.h (+4/-0) adchpp/Util.cpp (+5/-1) adchpp/Util.h (+2/-1) adchppd/adchppd.cpp (+7/-0) changelog.txt (+7/-0) etc/adchpp.xml (+13/-2) swig/adchpp.i (+6/-3) swig/lua.i (+1/-1) |
To merge this branch: | bzr merge lp:~maksis/adchpp/adchpp-hbri |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Dcplusplus-team | Pending | ||
Review via email: mp+194959@code.launchpad.net |
Commit message
Description of the change
* Add support for hybrid IPv4/IPv6 client connectivity: http://
* [L#1088638] Allow clients to reconnect in event of overflow
* [L#1106226] Fix a crash when joining the hub with a local IPv6 address
* Make login timeout work independently from other connecting users
* Allow configuring custom bind addresses
> hmm, it's unfortunate i forgot to answer that forum post but i still don't see
> why this has to be a new extension, and especially why it needs a new
> extension.
especially why it needs a new ADC command*
maksis (maksis) wrote : | # |
> hmm, it's unfortunate i forgot to answer that forum post
I don't think that it's too late yet. Starting a third thread for protocol discussion makes it even more difficult to track later.
Janne (barajag) wrote : | # |
it's fun to see Maksis work as usual. fix the big bugs too while you are working hehe
Nice work m8
Janne (barajag) wrote : | # |
is Adch++ dead now or what??????????
Unmerged revisions
- 665. By maksis
-
Sync
- 664. By maksis
-
Merge
- 663. By maksis
-
Merge
- 662. By maksis
-
Don't strip supports for the secondary IP protocol on INF updates
- 661. By maksis
-
Remove string::pop_back() for better compatibility
- 660. By maksis
-
Readd 629 and 630
- 659. By maksis
-
Revert some changes, update changelog
- 658. By maksis
-
- Remove extra TCP/UDP supports from clients
- Dont advertise the HBRI support if there is no configured hub address for both protocols - 657. By maksis
-
HBRI works also for registered users
- 656. By maksis
-
Resolve the configured hub addresses, bug fixes
Preview Diff
1 | === modified file 'adchpp/AdcCommand.cpp' |
2 | --- adchpp/AdcCommand.cpp 2014-04-11 18:47:46 +0000 |
3 | +++ adchpp/AdcCommand.cpp 2014-05-01 19:31:53 +0000 |
4 | @@ -40,7 +40,7 @@ |
5 | AdcCommand::AdcCommand() : cmdInt(0), priority(PRIORITY_NORMAL), from(INVALID_SID), to(INVALID_SID), type(TYPE_INFO) { } |
6 | |
7 | AdcCommand::AdcCommand(Severity sev, Error err, const string& desc, char aType /* = TYPE_INFO */) : cmdInt(CMD_STA), priority(PRIORITY_NORMAL), from(HUB_SID), to(INVALID_SID), type(aType) { |
8 | - addParam(Util::toString(sev * 100 + err)); |
9 | + addParam((sev == SEV_SUCCESS && err == SUCCESS) ? "000" : Util::toString(sev * 100 + err)); |
10 | addParam(desc); |
11 | } |
12 | |
13 | |
14 | === modified file 'adchpp/AdcCommand.h' |
15 | --- adchpp/AdcCommand.h 2014-04-11 18:47:46 +0000 |
16 | +++ adchpp/AdcCommand.h 2014-05-01 19:31:53 +0000 |
17 | @@ -36,6 +36,7 @@ |
18 | }; |
19 | |
20 | enum Error { |
21 | + SUCCESS = 0, |
22 | ERROR_GENERIC = 0, |
23 | ERROR_HUB_GENERIC = 10, |
24 | ERROR_HUB_FULL = 11, |
25 | @@ -63,7 +64,8 @@ |
26 | ERROR_FILE_NOT_AVAILABLE = 51, |
27 | ERROR_FILE_PART_NOT_AVAILABLE = 52, |
28 | ERROR_SLOTS_FULL = 53, |
29 | - ERROR_NO_CLIENT_HASH = 54 |
30 | + ERROR_NO_CLIENT_HASH = 54, |
31 | + ERROR_HBRI_TIMEOUT = 55 |
32 | }; |
33 | |
34 | enum Severity { |
35 | @@ -109,6 +111,7 @@ |
36 | C(CMD, 'C','M','D'); |
37 | C(NAT, 'N','A','T'); |
38 | C(RNT, 'R','N','T'); |
39 | + C(TCP, 'T','C','P'); |
40 | #undef C |
41 | |
42 | static const uint32_t HUB_SID = static_cast<uint32_t>(-1); |
43 | @@ -225,6 +228,7 @@ |
44 | C(CMD); |
45 | C(NAT); |
46 | C(RNT); |
47 | + C(TCP); |
48 | default: |
49 | dcdebug("Unknown ADC command: %.50s\n", cmd.toString().c_str()); |
50 | return true; |
51 | |
52 | === modified file 'adchpp/Client.h' |
53 | --- adchpp/Client.h 2014-04-11 18:47:46 +0000 |
54 | +++ adchpp/Client.h 2014-05-01 19:31:53 +0000 |
55 | @@ -43,6 +43,8 @@ |
56 | /** @param reason The statistic to update */ |
57 | ADCHPP_DLL virtual void disconnect(Util::Reason reason, const std::string &info = Util::emptyString) throw(); |
58 | const std::string& getIp() const throw() { return socket->getIp(); } |
59 | + bool getHbriParams(AdcCommand& cmd) const throw() { return socket->getHbriParams(cmd); } |
60 | + bool isV6() const { return socket->isV6(); } |
61 | |
62 | /** |
63 | * Set data mode for aBytes bytes. |
64 | |
65 | === modified file 'adchpp/ClientManager.cpp' |
66 | --- adchpp/ClientManager.cpp 2014-04-11 18:47:46 +0000 |
67 | +++ adchpp/ClientManager.cpp 2014-05-01 19:31:53 +0000 |
68 | @@ -20,6 +20,7 @@ |
69 | |
70 | #include "ClientManager.h" |
71 | |
72 | +#include "Core.h" |
73 | #include "File.h" |
74 | #include "Client.h" |
75 | #include "LogManager.h" |
76 | @@ -33,6 +34,15 @@ |
77 | #include <boost/asio/ip/address_v6.hpp> |
78 | #include <boost/locale.hpp> |
79 | |
80 | +#include <boost/range/algorithm/find.hpp> |
81 | +#include <boost/range/algorithm/find_if.hpp> |
82 | +#include <boost/range/algorithm/remove_if.hpp> |
83 | +#include <boost/range/adaptor/map.hpp> |
84 | + |
85 | +using boost::adaptors::map_values; |
86 | +using boost::range::find; |
87 | +using boost::range::find_if; |
88 | + |
89 | namespace adchpp { |
90 | |
91 | using namespace std; |
92 | @@ -43,10 +53,52 @@ |
93 | core(core), |
94 | hub(*this), |
95 | maxCommandSize(16 * 1024), |
96 | -logTimeout(30 * 1000) |
97 | +logTimeout(30 * 1000), |
98 | +hbriTimeout(5000) |
99 | { |
100 | + core.getSocketManager().addTimedJob(1000, std::bind(&ClientManager::onTimerSecond, this)); |
101 | +} |
102 | + |
103 | +void ClientManager::prepareSupports(bool addHbri) { |
104 | hub.addSupports(AdcCommand::toFourCC("BASE")); |
105 | hub.addSupports(AdcCommand::toFourCC("TIGR")); |
106 | + |
107 | + if (addHbri) |
108 | + hub.addSupports(AdcCommand::toFourCC("HBRI")); |
109 | +} |
110 | + |
111 | +void ClientManager::onTimerSecond() { |
112 | + // HBRI |
113 | + auto timeoutHbri = time::now() - time::millisec(hbriTimeout); |
114 | + for (auto i = hbriTokens.begin(); i != hbriTokens.end();) { |
115 | + if (timeoutHbri > i->second.second) { |
116 | + auto cc = dynamic_cast<Client*>(i->second.first); |
117 | + i = hbriTokens.erase(i); |
118 | + |
119 | + dcdebug("ClientManager: HBRI timeout in state %d\n", cc->getState()); |
120 | + |
121 | + std::string proto = cc->isV6() ? "IPv4" : "IPv6"; |
122 | + AdcCommand sta(AdcCommand::SEV_RECOVERABLE, AdcCommand::ERROR_HBRI_TIMEOUT, proto + " validation timed out"); |
123 | + cc->send(sta); |
124 | + |
125 | + cc->unsetFlag(Entity::FLAG_VALIDATE_HBRI); |
126 | + cc->stripProtocolSupports(); |
127 | + if (cc->getState() == Entity::STATE_HBRI) |
128 | + enterNormal(*cc, true, true); |
129 | + } else { |
130 | + i++; |
131 | + } |
132 | + } |
133 | + |
134 | + // Logins |
135 | + auto timeoutLogin = time::now() - time::millisec(getLogTimeout()); |
136 | + while (!logins.empty() && (timeoutLogin > logins.front().second)) { |
137 | + auto cc = logins.front().first; |
138 | + |
139 | + dcdebug("ClientManager: Login timeout in state %d\n", cc->getState()); |
140 | + cc->disconnect(Util::REASON_LOGIN_TIMEOUT); |
141 | + logins.pop_front(); |
142 | + } |
143 | } |
144 | |
145 | Bot* ClientManager::createBot(const Bot::SendHandler& handler) { |
146 | @@ -149,16 +201,6 @@ |
147 | |
148 | void ClientManager::onConnected(Client& c) throw() { |
149 | dcdebug("%s connected\n", AdcCommand::fromSID(c.getSID()).c_str()); |
150 | - // First let's check if any clients have passed the login timeout... |
151 | - auto timeout = time::now() - time::millisec(getLogTimeout()); |
152 | - |
153 | - while(!logins.empty() && (timeout > logins.front().second)) { |
154 | - Client* cc = logins.front().first; |
155 | - |
156 | - dcdebug("ClientManager: Login timeout in state %d\n", cc->getState()); |
157 | - cc->disconnect(Util::REASON_LOGIN_TIMEOUT); |
158 | - logins.pop_front(); |
159 | - } |
160 | |
161 | logins.push_back(make_pair(&c, time::now())); |
162 | |
163 | @@ -225,6 +267,7 @@ |
164 | badState(c, cmd); |
165 | return false; |
166 | } |
167 | + |
168 | return true; |
169 | } |
170 | |
171 | @@ -245,26 +288,32 @@ |
172 | } |
173 | |
174 | bool ClientManager::verifyINF(Entity& c, AdcCommand& cmd) throw() { |
175 | + if (!verifyCID(c, cmd)) |
176 | + return false; |
177 | + |
178 | + if (!verifyNick(c, cmd)) |
179 | + return false; |
180 | + |
181 | + if (cmd.getParam("DE", 0, strtmp)) { |
182 | + if (!Util::validateCharset(strtmp, 32)) { |
183 | + disconnect(c, Util::REASON_INVALID_DESCRIPTION, "Invalid character in description"); |
184 | + return false; |
185 | + } |
186 | + } |
187 | + |
188 | Client* cc = dynamic_cast<Client*>(&c); |
189 | |
190 | if(cc) { |
191 | - if(!verifyIp(*cc, cmd)) |
192 | - return false; |
193 | - } |
194 | - |
195 | - if(!verifyCID(c, cmd)) |
196 | - return false; |
197 | - |
198 | - if(!verifyNick(c, cmd)) |
199 | - return false; |
200 | - |
201 | - if(cmd.getParam("DE", 0, strtmp)) { |
202 | - if(!Util::validateCharset(strtmp, 32)) { |
203 | - disconnect(c, Util::REASON_INVALID_DESCRIPTION, "Invalid character in description"); |
204 | - return false; |
205 | - } |
206 | - } |
207 | + if(!verifyIp(*cc, cmd, false)) |
208 | + return false; |
209 | + } |
210 | + |
211 | c.updateFields(cmd); |
212 | + |
213 | + string tmp; |
214 | + if (cmd.getParam("SU", 0, tmp) && !c.isSet(Entity::FLAG_VALIDATE_HBRI) && c.getState() != Entity::STATE_HBRI) |
215 | + c.stripProtocolSupports(); |
216 | + |
217 | return true; |
218 | } |
219 | |
220 | @@ -307,13 +356,35 @@ |
221 | } |
222 | |
223 | if(overflowing > 3 && overflowing > (entities.size() / 4)) { |
224 | - disconnect(c, Util::REASON_NO_BANDWIDTH, "Not enough bandwidth available, please try again later", AdcCommand::ERROR_HUB_FULL); |
225 | + disconnect(c, Util::REASON_NO_BANDWIDTH, "Not enough bandwidth available, please try again later", AdcCommand::ERROR_HUB_FULL, Util::emptyString, 1); |
226 | return false; |
227 | } |
228 | |
229 | return true; |
230 | } |
231 | |
232 | +bool ClientManager::sendHBRI(Entity& c) { |
233 | + if (c.hasSupport(AdcCommand::toFourCC("HBRI"))) { |
234 | + AdcCommand cmd(AdcCommand::CMD_TCP); |
235 | + if (!dynamic_cast<Client*>(&c)->getHbriParams(cmd)) { |
236 | + return false; |
237 | + } |
238 | + |
239 | + c.setFlag(Entity::FLAG_VALIDATE_HBRI); |
240 | + if (c.getState() != Entity::STATE_NORMAL) |
241 | + c.setState(Entity::STATE_HBRI); |
242 | + |
243 | + auto token = Util::toString(Util::rand()); |
244 | + hbriTokens.insert(make_pair(token, make_pair(&c, time::now()))); |
245 | + |
246 | + cmd.addParam("TO", token); |
247 | + c.send(cmd); |
248 | + return true; |
249 | + } |
250 | + |
251 | + return false; |
252 | +} |
253 | + |
254 | bool ClientManager::handle(AdcCommand::INF, Entity& c, AdcCommand& cmd) throw() { |
255 | if(c.getState() != Entity::STATE_IDENTIFY && c.getState() != Entity::STATE_NORMAL) { |
256 | badState(c, cmd); |
257 | @@ -335,23 +406,98 @@ |
258 | return true; |
259 | } |
260 | |
261 | -bool ClientManager::verifyIp(Client& c, AdcCommand& cmd) throw() { |
262 | +static const int allowedCount = 3; |
263 | +static const char* allowedV4[allowedCount] = { "I4", "U4", "SU" }; |
264 | +static const char* allowedV6[allowedCount] = { "I6", "U6", "SU" }; |
265 | +bool ClientManager::handle(AdcCommand::TCP, Entity& c, AdcCommand& cmd) throw() { |
266 | + dcdebug("Received HBRI TCP: %s", cmd.toString().c_str()); |
267 | + |
268 | + string error; |
269 | + string token; |
270 | + if(cmd.getParam("TO", 0, token)) { |
271 | + auto p = hbriTokens.find(token); |
272 | + if (p != hbriTokens.end()) { |
273 | + Client* mainCC = dynamic_cast<Client*>(p->second.first); |
274 | + mainCC->unsetFlag(Entity::FLAG_VALIDATE_HBRI); |
275 | + |
276 | + if (mainCC->getState() != Entity::STATE_HBRI && mainCC->getState() != Entity::STATE_NORMAL) { |
277 | + badState(c, cmd); |
278 | + return false; |
279 | + } |
280 | + |
281 | + hbriTokens.erase(p); |
282 | + |
283 | + if (!verifyIp(*dynamic_cast<Client*>(&c), cmd, true)) |
284 | + return false; |
285 | + |
286 | + // disconnect the validation connection |
287 | + AdcCommand sta(AdcCommand::SEV_SUCCESS, AdcCommand::SUCCESS, "Validation succeed"); |
288 | + c.send(sta); |
289 | + c.disconnect(Util::REASON_HBRI); |
290 | + |
291 | + // remove extra parameters |
292 | + auto& params = cmd.getParameters(); |
293 | + const auto& allowed = dynamic_cast<Client*>(&c)->isV6() ? allowedV6 : allowedV4; |
294 | + |
295 | + params.erase(boost::remove_if(params, [&](const string& s) { |
296 | + return find(allowed, allowed + allowedCount, s.substr(0, 2)) == &allowed[allowedCount]; |
297 | + }), params.end()); |
298 | + |
299 | + // update the fields for the main entity |
300 | + mainCC->updateFields(cmd); |
301 | + |
302 | + if (mainCC->getState() == Entity::STATE_HBRI) { |
303 | + // continue with the normal login |
304 | + enterNormal(*mainCC, true, true); |
305 | + } else { |
306 | + // send the updated fields |
307 | + AdcCommand inf(AdcCommand::CMD_INF, AdcCommand::TYPE_BROADCAST, mainCC->getSID()); |
308 | + inf.getParameters() = cmd.getParameters(); |
309 | + sendToAll(inf.getBuffer()); |
310 | + } |
311 | + return true; |
312 | + } else { |
313 | + error = "Unknown validation token"; |
314 | + } |
315 | + } else { |
316 | + error = "Validation token missing"; |
317 | + } |
318 | + |
319 | + dcassert(!error.empty()); |
320 | + AdcCommand sta(AdcCommand::SEV_FATAL, AdcCommand::ERROR_LOGIN_GENERIC, error); |
321 | + c.send(sta); |
322 | + |
323 | + c.disconnect(Util::REASON_HBRI); |
324 | + return true; |
325 | +} |
326 | + |
327 | +bool ClientManager::verifyIp(Client& c, AdcCommand& cmd, bool isHbriConn) throw() { |
328 | if(c.isSet(Entity::FLAG_OK_IP)) |
329 | return true; |
330 | |
331 | using namespace boost::asio::ip; |
332 | |
333 | - auto remote = address::from_string(c.getIp()); |
334 | + address remote; |
335 | + |
336 | + try { |
337 | + remote = address::from_string(c.getIp()); |
338 | + } catch(const boost::system::system_error&) { |
339 | + printf("Error when reading IP %s\n", c.getIp().c_str()); |
340 | + return false; |
341 | + } |
342 | + |
343 | std::string ip; |
344 | |
345 | - if(remote.is_v4() || (remote.is_v6() && remote.to_v6().is_v4_mapped())) { |
346 | + bool doValidation = false; |
347 | + if (!c.isV6()) { |
348 | auto v4 = remote.is_v4() ? remote.to_v4() : remote.to_v6().to_v4(); |
349 | |
350 | if(cmd.getParam("I4", 0, ip)) { |
351 | dcdebug("%s verifying IP %s\n", AdcCommand::fromSID(c.getSID()).c_str(), ip.c_str()); |
352 | if(ip.empty() || address_v4::from_string(ip) == address_v4::any()) { |
353 | cmd.delParam("I4", 0); |
354 | - } else if(address_v4::from_string(ip) != v4 && !Util::isPrivateIp(c.getIp())) { |
355 | + cmd.addParam("I4", c.getIp()); |
356 | + } else if(address_v4::from_string(ip) != v4 && !Util::isPrivateIp(c.getIp(), false)) { |
357 | disconnect(c, Util::REASON_INVALID_IP, "Your IP is " + c.getIp() + |
358 | ", reconfigure your client settings", AdcCommand::ERROR_BAD_IP, "IP" + c.getIp()); |
359 | return false; |
360 | @@ -360,21 +506,24 @@ |
361 | } |
362 | } |
363 | |
364 | - if(!c.hasField("I4")) { |
365 | - c.setField("I4", v4.to_string()); |
366 | - } |
367 | - |
368 | - if(c.getState() != Entity::STATE_NORMAL) { |
369 | - cmd.addParam("I4", v4.to_string()); |
370 | - } |
371 | - |
372 | - cmd.delParam("I6", 0); // We can't check this so we remove it instead...fix? |
373 | - } else if(remote.is_v6()) { |
374 | + if (!isHbriConn) { |
375 | + if(!c.hasField("I4")) { |
376 | + c.setField("I4", v4.to_string()); |
377 | + } |
378 | + |
379 | + string tmp; |
380 | + doValidation = cmd.getParam("I6", 0, tmp) && !tmp.empty(); |
381 | + } |
382 | + |
383 | + cmd.delParam("U6", 0); |
384 | + cmd.delParam("I6", 0); |
385 | + } else { |
386 | if(cmd.getParam("I6", 0, ip)) { |
387 | dcdebug("%s verifying IPv6 %s\n", AdcCommand::fromSID(c.getSID()).c_str(), ip.c_str()); |
388 | if(ip.empty() || address_v6::from_string(ip) == address_v6::any()) { |
389 | cmd.delParam("I6", 0); |
390 | - } else if(address_v6::from_string(ip) != remote.to_v6() && !Util::isPrivateIp(c.getIp())) { |
391 | + cmd.addParam("I6", c.getIp()); |
392 | + } else if(address_v6::from_string(ip) != remote.to_v6() && !Util::isPrivateIp(c.getIp(), true)) { |
393 | disconnect(c, Util::REASON_INVALID_IP, "Your IP is " + c.getIp() + |
394 | ", reconfigure your client settings", AdcCommand::ERROR_BAD_IP, "IP" + c.getIp()); |
395 | return false; |
396 | @@ -383,15 +532,25 @@ |
397 | } |
398 | } |
399 | |
400 | - if(!c.hasField("I6")) { |
401 | - c.setField("I6", c.getIp()); |
402 | - } |
403 | - |
404 | - if(c.getState() != Entity::STATE_NORMAL) { |
405 | - cmd.addParam("I6", c.getIp()); |
406 | - } |
407 | - |
408 | - cmd.delParam("I4", 0); // We can't check this so we remove it instead...fix? |
409 | + if (!isHbriConn) { |
410 | + if (!c.hasField("I6")) { |
411 | + c.setField("I6", c.getIp()); |
412 | + } |
413 | + |
414 | + string tmp; |
415 | + doValidation = cmd.getParam("I4", 0, tmp) && !tmp.empty(); |
416 | + } |
417 | + |
418 | + cmd.delParam("I4", 0); |
419 | + cmd.delParam("U4", 0); |
420 | + } |
421 | + |
422 | + if (doValidation) { |
423 | + if (c.getState() == Entity::STATE_NORMAL) { |
424 | + sendHBRI(c); |
425 | + } else { |
426 | + c.setFlag(Entity::FLAG_VALIDATE_HBRI); |
427 | + } |
428 | } |
429 | |
430 | return true; |
431 | @@ -516,7 +675,7 @@ |
432 | signalState_(c, oldState); |
433 | } |
434 | |
435 | -void ClientManager::disconnect(Entity& c, Util::Reason reason, const std::string& info, AdcCommand::Error error, const std::string& staParam) { |
436 | +void ClientManager::disconnect(Entity& c, Util::Reason reason, const std::string& info, AdcCommand::Error error, const std::string& staParam, int aReconnectTime) { |
437 | // send a fatal STA |
438 | AdcCommand sta(AdcCommand::SEV_FATAL, error, info); |
439 | if(!staParam.empty()) |
440 | @@ -525,7 +684,7 @@ |
441 | |
442 | // send a QUI |
443 | c.send(AdcCommand(AdcCommand::CMD_QUI).addParam(AdcCommand::fromSID(c.getSID())) |
444 | - .addParam("DI", "1").addParam("MS", info).addParam("TL", "-1")); |
445 | + .addParam("DI", "1").addParam("MS", info).addParam("TL", Util::toString(aReconnectTime))); |
446 | |
447 | c.disconnect(reason); |
448 | } |
449 | @@ -562,6 +721,14 @@ |
450 | } |
451 | |
452 | bool ClientManager::enterNormal(Entity& c, bool sendData, bool sendOwnInf) throw() { |
453 | + if (c.isSet(Entity::FLAG_VALIDATE_HBRI)) { |
454 | + if (sendHBRI(c)) { |
455 | + return false; |
456 | + } |
457 | + |
458 | + c.unsetFlag(Entity::FLAG_VALIDATE_HBRI); |
459 | + } |
460 | + |
461 | dcassert(c.getState() == Entity::STATE_IDENTIFY || c.getState() == Entity::STATE_VERIFY); |
462 | dcdebug("%s entering NORMAL\n", AdcCommand::fromSID(c.getSID()).c_str()); |
463 | |
464 | @@ -596,6 +763,13 @@ |
465 | if(i != logins.end()) { |
466 | logins.erase(i); |
467 | } |
468 | + |
469 | + if (e.hasSupport(AdcCommand::toFourCC("HBRI"))) { |
470 | + auto i = find_if(hbriTokens | map_values, CompareFirst<Entity*, time::ptime>(c)).base(); |
471 | + if (i != hbriTokens.end()) { |
472 | + hbriTokens.erase(i); |
473 | + } |
474 | + } |
475 | } |
476 | |
477 | void ClientManager::removeEntity(Entity& c, Util::Reason reason, const std::string &info) throw() { |
478 | @@ -644,4 +818,4 @@ |
479 | removeEntity(c, reason, info); |
480 | } |
481 | |
482 | -} |
483 | +} |
484 | \ No newline at end of file |
485 | |
486 | === modified file 'adchpp/ClientManager.h' |
487 | --- adchpp/ClientManager.h 2014-04-11 18:47:46 +0000 |
488 | +++ adchpp/ClientManager.h 2014-05-01 19:31:53 +0000 |
489 | @@ -131,7 +131,7 @@ |
490 | /** |
491 | * Verify that IP is correct and replace any zero addresses. |
492 | */ |
493 | - ADCHPP_DLL bool verifyIp(Client& c, AdcCommand& cmd) throw(); |
494 | + ADCHPP_DLL bool verifyIp(Client& c, AdcCommand& cmd, bool isHbriConn) throw(); |
495 | |
496 | /** |
497 | * Verify that CID is correct and corresponds to PID |
498 | @@ -169,10 +169,13 @@ |
499 | void setMaxCommandSize(size_t newSize) { maxCommandSize = newSize; } |
500 | size_t getMaxCommandSize() const { return maxCommandSize; } |
501 | |
502 | + void setHbriTimeout(size_t millis) { hbriTimeout = millis; } |
503 | + size_t getHbriTimeout() const { return hbriTimeout; } |
504 | void setLogTimeout(size_t millis) { logTimeout = millis; } |
505 | size_t getLogTimeout() const { return logTimeout; } |
506 | |
507 | Core &getCore() const { return core; } |
508 | + void prepareSupports(bool addHbri); |
509 | private: |
510 | friend class Core; |
511 | friend class Client; |
512 | @@ -183,6 +186,9 @@ |
513 | |
514 | std::list<std::pair<Client*, time::ptime> > logins; |
515 | |
516 | + typedef std::unordered_map<std::string, std::pair<Entity*, time::ptime>> TokenMap; |
517 | + TokenMap hbriTokens; |
518 | + |
519 | EntityMap entities; |
520 | typedef std::unordered_map<std::string, Entity*> NickMap; |
521 | NickMap nicks; |
522 | @@ -193,6 +199,7 @@ |
523 | |
524 | size_t maxCommandSize; |
525 | size_t logTimeout; |
526 | + size_t hbriTimeout; |
527 | |
528 | // Temporary string to use whenever a temporary string is needed (to avoid (de)allocating memory all the time...) |
529 | std::string strtmp; |
530 | @@ -203,6 +210,7 @@ |
531 | |
532 | uint32_t makeSID(); |
533 | |
534 | + bool sendHBRI(Entity& c); |
535 | void maybeSend(Entity& c, const AdcCommand& cmd); |
536 | |
537 | void removeLogins(Entity& c) throw(); |
538 | @@ -210,6 +218,7 @@ |
539 | |
540 | bool handle(AdcCommand::SUP, Entity& c, AdcCommand& cmd) throw(); |
541 | bool handle(AdcCommand::INF, Entity& c, AdcCommand& cmd) throw(); |
542 | + bool handle(AdcCommand::TCP, Entity& c, AdcCommand& cmd) throw(); |
543 | bool handleDefault(Entity& c, AdcCommand& cmd) throw(); |
544 | |
545 | template<typename T> bool handle(T, Entity& c, AdcCommand& cmd) throw() { return handleDefault(c, cmd); } |
546 | @@ -225,7 +234,7 @@ |
547 | void badState(Entity& c, const AdcCommand& cmd) throw(); |
548 | /** send a fatal STA, a QUI with TL-1, then disconnect. */ |
549 | void disconnect(Entity& c, Util::Reason reason, const std::string& info, |
550 | - AdcCommand::Error error = AdcCommand::ERROR_PROTOCOL_GENERIC, const std::string& staParam = Util::emptyString); |
551 | + AdcCommand::Error error = AdcCommand::ERROR_PROTOCOL_GENERIC, const std::string& staParam = Util::emptyString, int aReconnectTime = -1); |
552 | |
553 | SignalConnected::Signal signalConnected_; |
554 | SignalReady::Signal signalReady_; |
555 | @@ -236,6 +245,7 @@ |
556 | SignalDisconnected::Signal signalDisconnected_; |
557 | |
558 | ClientManager(Core &core) throw(); |
559 | + void onTimerSecond(); |
560 | }; |
561 | |
562 | } |
563 | |
564 | === modified file 'adchpp/Entity.cpp' |
565 | --- adchpp/Entity.cpp 2014-04-11 18:47:46 +0000 |
566 | +++ adchpp/Entity.cpp 2014-05-01 19:31:53 +0000 |
567 | @@ -48,10 +48,9 @@ |
568 | |
569 | if(code == AdcCommand::toField("SU")) { |
570 | filters.clear(); |
571 | - |
572 | - if((value.size() + 1) % 5 == 0) { |
573 | + if ((value.size() + 1) % 5 == 0) { |
574 | filters.reserve((value.size() + 1) / 5); |
575 | - for(size_t i = 0; i < value.size(); i += 5) { |
576 | + for (size_t i = 0; i < value.size(); i += 5) { |
577 | filters.push_back(AdcCommand::toFourCC(value.data() + i)); |
578 | } |
579 | } |
580 | @@ -154,6 +153,41 @@ |
581 | } |
582 | } |
583 | |
584 | +bool Entity::hasClientSupport(uint32_t feature) const { |
585 | + return std::find(filters.begin(), filters.end(), feature) != filters.end(); |
586 | +} |
587 | + |
588 | +bool Entity::removeClientSupport(uint32_t feature) { |
589 | + auto f = std::find(filters.begin(), filters.end(), feature); |
590 | + if (f == filters.end()) { |
591 | + return false; |
592 | + } |
593 | + |
594 | + filters.erase(f); |
595 | + |
596 | + auto& supports = fields.find(AdcCommand::toField("SU"))->second; |
597 | + |
598 | + auto p = supports.find(AdcCommand::fromFourCC(feature)); |
599 | + dcassert(p != std::string::npos); |
600 | + supports.erase(p, 5); |
601 | + |
602 | + if (!supports.empty() && supports.back() == ',') |
603 | + supports.erase(supports.size() - 1); |
604 | + |
605 | + return true; |
606 | +} |
607 | + |
608 | +static const int protoSupportCount = 2; |
609 | +static uint32_t supports4[protoSupportCount] = { AdcCommand::toFourCC("TCP4"), AdcCommand::toFourCC("UDP4") }; |
610 | +static uint32_t supports6[protoSupportCount] = { AdcCommand::toFourCC("TCP6"), AdcCommand::toFourCC("UDP6") }; |
611 | + |
612 | +void Entity::stripProtocolSupports() throw() { |
613 | + const auto& sup = dynamic_cast<Client*>(this)->isV6() ? supports4 : supports6; |
614 | + for (auto i = 0; i < protoSupportCount; ++i) { |
615 | + removeClientSupport(sup[i]); |
616 | + } |
617 | +} |
618 | + |
619 | bool Entity::isFiltered(const std::string& features) const { |
620 | if(filters.empty()) { |
621 | return true; |
622 | |
623 | === modified file 'adchpp/Entity.h' |
624 | --- adchpp/Entity.h 2014-04-11 18:47:46 +0000 |
625 | +++ adchpp/Entity.h 2014-05-01 19:31:53 +0000 |
626 | @@ -33,6 +33,8 @@ |
627 | enum State { |
628 | /** Initial protocol negotiation (wait for SUP) */ |
629 | STATE_PROTOCOL, |
630 | + /** Validating the secondary address */ |
631 | + STATE_HBRI, |
632 | /** Identify the connecting client (wait for INF) */ |
633 | STATE_IDENTIFY, |
634 | /** Verify the client (wait for PAS) */ |
635 | @@ -63,7 +65,10 @@ |
636 | FLAG_OK_IP = 0x400, |
637 | |
638 | /** This entity is now a ghost being disconnected, totally ignored by ADCH++ */ |
639 | - FLAG_GHOST = 0x800 |
640 | + FLAG_GHOST = 0x800, |
641 | + |
642 | + /** Set in the login phase if the users provides an IP for another protocol **/ |
643 | + FLAG_VALIDATE_HBRI = 0x1000 |
644 | }; |
645 | |
646 | |
647 | @@ -87,6 +92,12 @@ |
648 | ADCHPP_DLL bool hasSupport(uint32_t feature) const; |
649 | ADCHPP_DLL bool removeSupports(uint32_t feature); |
650 | |
651 | + ADCHPP_DLL bool hasClientSupport(uint32_t feature) const; |
652 | + ADCHPP_DLL bool removeClientSupport(uint32_t feature); |
653 | + |
654 | + /** Remove supports for the protocol that wasn't used for connecting **/ |
655 | + ADCHPP_DLL void stripProtocolSupports() throw(); |
656 | + |
657 | ADCHPP_DLL const BufferPtr& getSUP() const; |
658 | |
659 | uint32_t getSID() const { return sid; } |
660 | |
661 | === modified file 'adchpp/ManagedSocket.cpp' |
662 | --- adchpp/ManagedSocket.cpp 2014-04-11 18:47:46 +0000 |
663 | +++ adchpp/ManagedSocket.cpp 2014-05-01 19:31:53 +0000 |
664 | @@ -22,18 +22,21 @@ |
665 | |
666 | #include "SocketManager.h" |
667 | |
668 | +#include <boost/asio/ip/address.hpp> |
669 | + |
670 | namespace adchpp { |
671 | |
672 | using namespace std; |
673 | |
674 | using namespace boost::asio; |
675 | |
676 | -ManagedSocket::ManagedSocket(SocketManager &sm, const AsyncStreamPtr &sock_) : |
677 | +ManagedSocket::ManagedSocket(SocketManager &sm, const AsyncStreamPtr &sock_, const ServerInfoPtr& aServer) : |
678 | sock(sock_), |
679 | overflow(time::not_a_date_time), |
680 | disc(time::not_a_date_time), |
681 | lastWrite(time::not_a_date_time), |
682 | - sm(sm) |
683 | + sm(sm), |
684 | + server(aServer) |
685 | { } |
686 | |
687 | ManagedSocket::~ManagedSocket() throw() { |
688 | @@ -251,6 +254,39 @@ |
689 | std::string info; |
690 | }; |
691 | |
692 | +bool ManagedSocket::getHbriParams(AdcCommand& cmd) const throw() { |
693 | + if (!isV6()) { |
694 | + if (!server->address6.empty()) { |
695 | + cmd.addParam("I6", server->address6); |
696 | + } else { |
697 | + return false; |
698 | + } |
699 | + |
700 | + cmd.addParam("P6", server->port); |
701 | + } else { |
702 | + if (!server->address4.empty()) { |
703 | + cmd.addParam("I4", server->address4); |
704 | + } else { |
705 | + return false; |
706 | + } |
707 | + |
708 | + cmd.addParam("P4", server->port); |
709 | + } |
710 | + |
711 | + return true; |
712 | +} |
713 | + |
714 | +bool ManagedSocket::isV6() const throw() { |
715 | + using namespace boost::asio::ip; |
716 | + |
717 | + address remote; |
718 | + remote = address::from_string(ip); |
719 | + if (remote.is_v4() || (remote.is_v6() && remote.to_v6().is_v4_mapped())) |
720 | + return false; |
721 | + |
722 | + return true; |
723 | +} |
724 | + |
725 | void ManagedSocket::disconnect(Util::Reason reason, const std::string &info) throw() { |
726 | if(disconnecting()) { |
727 | return; |
728 | |
729 | === modified file 'adchpp/ManagedSocket.h' |
730 | --- adchpp/ManagedSocket.h 2014-04-11 18:47:46 +0000 |
731 | +++ adchpp/ManagedSocket.h 2014-05-01 19:31:53 +0000 |
732 | @@ -22,6 +22,8 @@ |
733 | #include "common.h" |
734 | |
735 | #include "forward.h" |
736 | + |
737 | +#include "AdcCommand.h" |
738 | #include "Signal.h" |
739 | #include "Util.h" |
740 | #include "Buffer.h" |
741 | @@ -35,7 +37,7 @@ |
742 | */ |
743 | class ManagedSocket : private boost::noncopyable, public enable_shared_from_this<ManagedSocket> { |
744 | public: |
745 | - ManagedSocket(SocketManager &sm, const AsyncStreamPtr& sock_); |
746 | + ManagedSocket(SocketManager &sm, const AsyncStreamPtr& sock_, const ServerInfoPtr& aServer); |
747 | |
748 | /** Asynchronous write */ |
749 | ADCHPP_DLL void write(const BufferPtr& buf, bool lowPrio = false) throw(); |
750 | @@ -68,6 +70,8 @@ |
751 | |
752 | ~ManagedSocket() throw(); |
753 | |
754 | + bool getHbriParams(AdcCommand& cmd) const throw(); |
755 | + bool isV6() const throw(); |
756 | private: |
757 | friend class SocketManager; |
758 | friend class SocketFactory; |
759 | @@ -110,6 +114,8 @@ |
760 | FailedHandler failedHandler; |
761 | |
762 | SocketManager &sm; |
763 | + |
764 | + ServerInfoPtr server; |
765 | }; |
766 | |
767 | } |
768 | |
769 | === modified file 'adchpp/ServerInfo.h' |
770 | --- adchpp/ServerInfo.h 2014-04-11 18:47:46 +0000 |
771 | +++ adchpp/ServerInfo.h 2014-05-01 19:31:53 +0000 |
772 | @@ -22,7 +22,10 @@ |
773 | namespace adchpp { |
774 | |
775 | struct ServerInfo { |
776 | - std::string ip; |
777 | + std::string bind4; |
778 | + std::string bind6; |
779 | + std::string address4; |
780 | + std::string address6; |
781 | std::string port; |
782 | |
783 | struct TLSInfo { |
784 | |
785 | === modified file 'adchpp/SocketManager.cpp' |
786 | --- adchpp/SocketManager.cpp 2014-04-11 18:47:46 +0000 |
787 | +++ adchpp/SocketManager.cpp 2014-05-01 19:31:53 +0000 |
788 | @@ -20,6 +20,7 @@ |
789 | |
790 | #include "SocketManager.h" |
791 | |
792 | +#include "ClientManager.h" |
793 | #include "LogManager.h" |
794 | #include "ManagedSocket.h" |
795 | #include "ServerInfo.h" |
796 | @@ -47,7 +48,9 @@ |
797 | bufferSize(1024), |
798 | maxBufferSize(16 * 1024), |
799 | overflowTimeout(60 * 1000), |
800 | -disconnectTimeout(10 * 1000) |
801 | +disconnectTimeout(10 * 1000), |
802 | +hasV4Address(false), |
803 | +hasV6Address(false) |
804 | { |
805 | } |
806 | |
807 | @@ -192,10 +195,11 @@ |
808 | |
809 | class SocketFactory : public enable_shared_from_this<SocketFactory>, boost::noncopyable { |
810 | public: |
811 | - SocketFactory(SocketManager& sm, const SocketManager::IncomingHandler& handler_, const ServerInfo& info, const ip::tcp::endpoint& endpoint) : |
812 | + SocketFactory(SocketManager& sm, const SocketManager::IncomingHandler& handler_, ServerInfoPtr& info, const ip::tcp::endpoint& endpoint) : |
813 | sm(sm), |
814 | acceptor(sm.io), |
815 | - handler(handler_) |
816 | + handler(handler_), |
817 | + si(info) |
818 | { |
819 | acceptor.open(endpoint.protocol()); |
820 | acceptor.set_option(socket_base::reuse_address(true)); |
821 | @@ -203,21 +207,23 @@ |
822 | acceptor.set_option(ip::v6_only(true)); |
823 | } |
824 | |
825 | + auto a = endpoint.address().to_string(); |
826 | + |
827 | acceptor.bind(endpoint); |
828 | acceptor.listen(socket_base::max_connections); |
829 | |
830 | LOGC(sm.getCore(), SocketManager::className, |
831 | "Listening on " + formatEndpoint(endpoint) + |
832 | - " (Encrypted: " + (info.secure() ? "Yes)" : "No)")); |
833 | + " (Encrypted: " + (info->secure() ? "Yes)" : "No)")); |
834 | |
835 | #ifdef HAVE_OPENSSL |
836 | - if(info.secure()) { |
837 | + if(info->secure()) { |
838 | context.reset(new ssl::context(sm.io, ssl::context::tlsv1_server)); |
839 | context->set_options(ssl::context::no_sslv2 | ssl::context::no_sslv3 | ssl::context::single_dh_use); |
840 | //context->set_password_callback(boost::bind(&server::get_password, this)); |
841 | - context->use_certificate_chain_file(info.TLSParams.cert); |
842 | - context->use_private_key_file(info.TLSParams.pkey, ssl::context::pem); |
843 | - context->use_tmp_dh_file(info.TLSParams.dh); |
844 | + context->use_certificate_chain_file(info->TLSParams.cert); |
845 | + context->use_private_key_file(info->TLSParams.pkey, ssl::context::pem); |
846 | + context->use_tmp_dh_file(info->TLSParams.dh); |
847 | } |
848 | #endif |
849 | } |
850 | @@ -230,12 +236,12 @@ |
851 | #ifdef HAVE_OPENSSL |
852 | if(context) { |
853 | auto s = make_shared<TLSSocketStream>(sm.io, *context); |
854 | - auto socket = make_shared<ManagedSocket>(sm, s); |
855 | + auto socket = make_shared<ManagedSocket>(sm, s, si); |
856 | acceptor.async_accept(s->sock.lowest_layer(), std::bind(&SocketFactory::handleAccept, shared_from_this(), std::placeholders::_1, socket)); |
857 | } else { |
858 | #endif |
859 | auto s = make_shared<SimpleSocketStream>(sm.io); |
860 | - auto socket = make_shared<ManagedSocket>(sm, s); |
861 | + auto socket = make_shared<ManagedSocket>(sm, s, si); |
862 | acceptor.async_accept(s->sock.lowest_layer(), std::bind(&SocketFactory::handleAccept, shared_from_this(), std::placeholders::_1, socket)); |
863 | #ifdef HAVE_OPENSSL |
864 | } |
865 | @@ -245,7 +251,9 @@ |
866 | void handleAccept(const error_code& ec, const ManagedSocketPtr& socket) { |
867 | if(!ec) { |
868 | socket->sock->setOptions(sm.getBufferSize()); |
869 | - socket->setIp(socket->sock->getIp()); |
870 | + auto ip = socket->sock->getIp(); |
871 | + auto p = ip.find("%"); |
872 | + socket->setIp(p != string::npos ? ip.substr(0, p) : ip); |
873 | } |
874 | |
875 | completeAccept(ec, socket); |
876 | @@ -263,37 +271,68 @@ |
877 | SocketManager &sm; |
878 | ip::tcp::acceptor acceptor; |
879 | SocketManager::IncomingHandler handler; |
880 | - |
881 | + ServerInfoPtr si; |
882 | #ifdef HAVE_OPENSSL |
883 | unique_ptr<ssl::context> context; |
884 | #endif |
885 | |
886 | }; |
887 | |
888 | +void SocketManager::prepareProtocol(ServerInfoPtr& si, bool v6) { |
889 | + const string proto = v6 ? "IPv6" : "IPv4"; |
890 | + try { |
891 | + using ip::tcp; |
892 | + tcp::resolver r(io); |
893 | + |
894 | + // Resolve the public address |
895 | + string& hubAddress = v6 ? si->address6 : si->address4; |
896 | + if (!hubAddress.empty()) { |
897 | + try { |
898 | + auto remote = r.resolve(tcp::resolver::query(v6 ? tcp::v6() : tcp::v4(), hubAddress, si->port, |
899 | + tcp::resolver::query::address_configured | tcp::resolver::query::passive)); |
900 | + hubAddress = remote->endpoint().address().to_string(); |
901 | + v6 ? hasV6Address = true : hasV4Address = true; |
902 | + } catch (const std::exception& e) { |
903 | + LOG(SocketManager::className, "Error when resolving the " + proto + " hub address " + hubAddress + ": " + e.what()); |
904 | + hubAddress = Util::emptyString; |
905 | + } |
906 | + } |
907 | + |
908 | + // Resolve the bind address |
909 | + auto local = r.resolve(tcp::resolver::query(v6 ? tcp::v6() : tcp::v4(), v6 ? si->bind6 : si->bind4, si->port, |
910 | + tcp::resolver::query::address_configured | tcp::resolver::query::passive)); |
911 | + |
912 | + for (auto i = local; i != tcp::resolver::iterator(); ++i) { |
913 | + auto factory = make_shared<SocketFactory>(*this, incomingHandler, si, *i); |
914 | + factory->prepareAccept(); |
915 | + factories.push_back(factory); |
916 | + } |
917 | + } catch (const std::exception& e) { |
918 | + LOG(SocketManager::className, "Error while loading " + proto + " server on port " + si->port + ": " + e.what()); |
919 | + } |
920 | +} |
921 | + |
922 | int SocketManager::run() { |
923 | + //Sleep(10000); |
924 | LOG(SocketManager::className, "Starting"); |
925 | |
926 | work.reset(new io_service::work(io)); |
927 | |
928 | for(auto i = servers.begin(), iend = servers.end(); i != iend; ++i) { |
929 | auto& si = *i; |
930 | - |
931 | - try { |
932 | - using ip::tcp; |
933 | - tcp::resolver r(io); |
934 | - auto local = r.resolve(tcp::resolver::query(si->ip, si->port, |
935 | - tcp::resolver::query::address_configured | tcp::resolver::query::passive)); |
936 | - |
937 | - for(auto i = local; i != tcp::resolver::iterator(); ++i) { |
938 | - SocketFactoryPtr factory = make_shared<SocketFactory>(*this, incomingHandler, *si, *i); |
939 | - factory->prepareAccept(); |
940 | - factories.push_back(factory); |
941 | - } |
942 | - } catch(const std::exception& e) { |
943 | - LOG(SocketManager::className, "Error while loading server on port " + si->port +": " + e.what()); |
944 | + bool listenAll = si->bind4.empty() && si->bind6.empty(); |
945 | + |
946 | + if (!si->bind4.empty() || listenAll) { |
947 | + prepareProtocol(si, false); |
948 | + } |
949 | + |
950 | + if (!si->bind6.empty() || listenAll) { |
951 | + prepareProtocol(si, true); |
952 | } |
953 | } |
954 | |
955 | + core.getClientManager().prepareSupports(hasV4Address && hasV6Address); |
956 | + |
957 | io.run(); |
958 | |
959 | io.reset(); |
960 | |
961 | === modified file 'adchpp/SocketManager.h' |
962 | --- adchpp/SocketManager.h 2014-04-11 18:47:46 +0000 |
963 | +++ adchpp/SocketManager.h 2014-05-01 19:31:53 +0000 |
964 | @@ -94,6 +94,7 @@ |
965 | friend class ManagedSocket; |
966 | friend class SocketFactory; |
967 | |
968 | + void prepareProtocol(ServerInfoPtr& si, bool v6); |
969 | void closeFactories(); |
970 | |
971 | Core &core; |
972 | @@ -126,6 +127,9 @@ |
973 | void onLoad(const SimpleXML& xml) throw(); |
974 | |
975 | SocketManager(Core &core); |
976 | + |
977 | + bool hasV4Address; |
978 | + bool hasV6Address; |
979 | }; |
980 | |
981 | } |
982 | |
983 | === modified file 'adchpp/Util.cpp' |
984 | --- adchpp/Util.cpp 2014-04-11 18:47:46 +0000 |
985 | +++ adchpp/Util.cpp 2014-05-01 19:31:53 +0000 |
986 | @@ -338,7 +338,11 @@ |
987 | } |
988 | #endif |
989 | |
990 | -bool Util::isPrivateIp(std::string const& ip) { |
991 | +bool Util::isPrivateIp(std::string const& ip, bool v6) { |
992 | + if (v6) { |
993 | + return strncmp(ip.c_str(), "fe80", 4) == 0; |
994 | + } |
995 | + |
996 | struct in_addr addr; |
997 | |
998 | addr.s_addr = inet_addr(ip.c_str()); |
999 | |
1000 | === modified file 'adchpp/Util.h' |
1001 | --- adchpp/Util.h 2014-04-11 18:47:46 +0000 |
1002 | +++ adchpp/Util.h 2014-05-01 19:31:53 +0000 |
1003 | @@ -102,6 +102,7 @@ |
1004 | REASON_INVALID_DESCRIPTION, |
1005 | REASON_WRITE_TIMEOUT, |
1006 | REASON_SOCKET_ERROR, |
1007 | + REASON_HBRI, |
1008 | REASON_LAST, |
1009 | }; |
1010 | |
1011 | @@ -228,7 +229,7 @@ |
1012 | static uint32_t rand(uint32_t low, uint32_t high) { return rand(high-low) + low; } |
1013 | static double randd() { return ((double)rand()) / ((double)0xffffffff); } |
1014 | |
1015 | - ADCHPP_DLL static bool isPrivateIp(std::string const& ip); |
1016 | + ADCHPP_DLL static bool isPrivateIp(std::string const& ip, bool v6); |
1017 | ADCHPP_DLL static bool validateCharset(std::string const& field, int p); |
1018 | }; |
1019 | |
1020 | |
1021 | === modified file 'adchppd/adchppd.cpp' |
1022 | --- adchppd/adchppd.cpp 2014-04-11 18:47:46 +0000 |
1023 | +++ adchppd/adchppd.cpp 2014-05-01 19:31:53 +0000 |
1024 | @@ -72,6 +72,8 @@ |
1025 | core.getSocketManager().setDisconnectTimeout(Util::toInt(xml.getChildData())); |
1026 | } else if(xml.getChildName() == "LogTimeout") { |
1027 | core.getClientManager().setLogTimeout(Util::toInt(xml.getChildData())); |
1028 | + } else if (xml.getChildName() == "HbriTimeout") { |
1029 | + core.getClientManager().setHbriTimeout(Util::toInt(xml.getChildData())); |
1030 | } |
1031 | } |
1032 | |
1033 | @@ -85,6 +87,11 @@ |
1034 | ServerInfoPtr server = make_shared<ServerInfo>(); |
1035 | server->port = xml.getChildAttrib("Port", Util::emptyString); |
1036 | |
1037 | + server->bind4 = xml.getChildAttrib("BindAddress4", Util::emptyString); |
1038 | + server->bind6 = xml.getChildAttrib("BindAddress6", Util::emptyString); |
1039 | + server->address4 = xml.getChildAttrib("HubAddress4", Util::emptyString); |
1040 | + server->address6 = xml.getChildAttrib("HubAddress6", Util::emptyString); |
1041 | + |
1042 | if(xml.getBoolChildAttrib("TLS")) { |
1043 | server->TLSParams.cert = File::makeAbsolutePath(xml.getChildAttrib("Certificate")); |
1044 | server->TLSParams.pkey = File::makeAbsolutePath(xml.getChildAttrib("PrivateKey")); |
1045 | |
1046 | === modified file 'changelog.txt' |
1047 | --- changelog.txt 2014-04-14 17:40:14 +0000 |
1048 | +++ changelog.txt 2014-05-01 19:31:53 +0000 |
1049 | @@ -2,6 +2,13 @@ |
1050 | * [L#1206293] Fix crashes after calling +reload |
1051 | * [L#1206293] Fix commands that output entity info |
1052 | |
1053 | +* Add support for hybrid IPv4/IPv6 client connectivity (maksis) |
1054 | +* [L#1088638] Allow clients to reconnect in event of overflow (maksis) |
1055 | +* [L#1106226] Fix a crash when joining the hub with a local IPv6 address (maksis) |
1056 | +* Make login timeout work independently from other connecting users (maksis) |
1057 | +* Allow configuring custom bind addresses (maksis) |
1058 | +* Improve Lua scripts |
1059 | + |
1060 | -- 2.11.1 2014-04-10 -- |
1061 | * Improve Lua scripts |
1062 | |
1063 | |
1064 | === modified file 'etc/adchpp.xml' |
1065 | --- etc/adchpp.xml 2013-07-19 19:47:27 +0000 |
1066 | +++ etc/adchpp.xml 2014-05-01 19:31:53 +0000 |
1067 | @@ -51,6 +51,10 @@ |
1068 | |
1069 | <!-- Timeout (ms) before disconnecting users whose login process is taking too long. --> |
1070 | <LogTimeout>10000</LogTimeout> |
1071 | + |
1072 | + <!-- Timeout (ms) before aborting validation for the secondary IP protocol. |
1073 | + The login procedure will continue normally with the primary IP protocol then. --> |
1074 | + <HbriTimeout>3000</HbriTimeout> |
1075 | </Settings> |
1076 | |
1077 | <Servers> |
1078 | @@ -59,15 +63,22 @@ |
1079 | |
1080 | To create secure connections, set TLS="1" and define the following (preferably absolute) |
1081 | paths: Certificate, PrivateKey, TrustedPath, DHParams. An example secure server setting: |
1082 | - <Server Port="2780" TLS="1" Certificate="certs/cacert.pem" PrivateKey="certs/privkey.pem" TrustedPath="certs/trusted/" DHParams="certs/dhparam.pem"/> |
1083 | + <Server Port="2780" TLS="1" Certificate="certs/cacert.pem" PrivateKey="certs/privkey.pem" TrustedPath="certs/trusted/" DHParams="certs/dhparam.pem" BindAddress4="0.0.0.0" BindAddress6="::"/> |
1084 | |
1085 | Simple OpenSSL commands to generate files used for secure connections: |
1086 | openssl genrsa -out privkey.pem 2048 |
1087 | openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095 |
1088 | openssl dhparam -outform PEM -out dhparam.pem 1024 |
1089 | - |
1090 | + |
1091 | Alternatively, you can use the cert generator contributed on |
1092 | <http://launchpadlibrarian.net/31960965/Cert_Generator.7z>. |
1093 | + |
1094 | + To allow hybrid connectivity, add address fields for the used protocols: HubAddress4 and HubAddress6. You may also use the same |
1095 | + DNS entry for both if it has A and AAAA records. You may also use plain IP addresses. |
1096 | + Example: |
1097 | + <Server Port="2780" HubAddress4="mydomain4.net" HubAddress6="mydomain6.net"/> |
1098 | + |
1099 | + Bind addresses may be set with: BindAddress4 and BindAddress6 (connections will be accepted for both protocols if none is set) |
1100 | |
1101 | --> |
1102 | <Server Port="2780"/> |
1103 | |
1104 | === modified file 'swig/adchpp.i' |
1105 | --- swig/adchpp.i 2013-07-19 19:47:27 +0000 |
1106 | +++ swig/adchpp.i 2014-05-01 19:31:53 +0000 |
1107 | @@ -126,7 +126,10 @@ |
1108 | typedef shared_ptr<ManagedConnection> ManagedConnectionPtr; |
1109 | |
1110 | struct ServerInfo { |
1111 | - std::string ip; |
1112 | + std::string bind4; |
1113 | + std::string bind6; |
1114 | + std::string address4; |
1115 | + std::string address6; |
1116 | std::string port; |
1117 | |
1118 | TLSInfo TLSParams; |
1119 | @@ -291,7 +294,7 @@ |
1120 | static uint32_t rand(uint32_t low, uint32_t high); |
1121 | static double randd(); |
1122 | |
1123 | - static bool isPrivateIp(std::string const& ip); |
1124 | + static bool isPrivateIp(std::string const& ip, bool v6); |
1125 | static bool validateCharset(std::string const& field, int p); |
1126 | |
1127 | }; |
1128 | @@ -723,7 +726,7 @@ |
1129 | bool verifyPassword(Entity& c, const std::string& password, const ByteVector& salt, const std::string& suppliedHash); |
1130 | bool verifyHashedPassword(Entity& c, const ByteVector& hashedPassword, int64_t hashedPasswordLen, |
1131 | const ByteVector& salt, const std::string& suppliedHash) throw(); |
1132 | - bool verifyIp(Client& c, AdcCommand& cmd) throw(); |
1133 | + bool verifyIp(Client& c, AdcCommand& cmd, bool isHbriConn) throw(); |
1134 | bool verifyCID(Entity& c, AdcCommand& cmd) throw(); |
1135 | bool verifyOverflow(Entity& c); |
1136 | void setState(Entity& c, Entity::State newState) throw(); |
1137 | |
1138 | === modified file 'swig/lua.i' |
1139 | --- swig/lua.i 2014-04-13 15:01:43 +0000 |
1140 | +++ swig/lua.i 2014-05-01 19:31:53 +0000 |
1141 | @@ -322,7 +322,7 @@ |
1142 | if(ret) { |
1143 | return *reinterpret_cast<SWIGLUA_REF*>(ret); |
1144 | } |
1145 | - return {0, 0}; |
1146 | + return SWIGLUA_REF(); |
1147 | } |
1148 | |
1149 | void setPluginData(const PluginDataHandle& handle, SWIGLUA_REF data) { |
hmm, it's unfortunate i forgot to answer that forum post but i still don't see why this has to be a new extension, and especially why it needs a new extension.
i exposed a simpler alternative here: <https:/ /bugs.launchpad .net/adchpp/ +bug/309402/ comments/ 40>
it relies on the quality of the PID/CID system, which is assumed to be reliable in ADC where hubs are trusted.