Merge lp:~maksis/adchpp/adchpp-hbri into lp:adchpp

Proposed by maksis
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
Reviewer Review Type Date Requested Status
Dcplusplus-team Pending
Review via email: mp+194959@code.launchpad.net

Description of the change

* Add support for hybrid IPv4/IPv6 client connectivity: http://www.dcbase.org/forum/viewtopic.php?f=55&t=771
* [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

To post a comment you must log in.
Revision history for this message
poy (poy) wrote :

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.

Revision history for this message
poy (poy) wrote :

> 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*

Revision history for this message
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.

lp:~maksis/adchpp/adchpp-hbri updated
661. By maksis

Remove string::pop_back() for better compatibility

Revision history for this message
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

Revision history for this message
Janne (barajag) wrote :

is Adch++ dead now or what??????????

lp:~maksis/adchpp/adchpp-hbri updated
662. By maksis

Don't strip supports for the secondary IP protocol on INF updates

663. By maksis

Merge

664. By maksis

Merge

665. By maksis

Sync

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'adchpp/AdcCommand.cpp'
--- adchpp/AdcCommand.cpp 2014-04-11 18:47:46 +0000
+++ adchpp/AdcCommand.cpp 2014-05-01 19:31:53 +0000
@@ -40,7 +40,7 @@
40AdcCommand::AdcCommand() : cmdInt(0), priority(PRIORITY_NORMAL), from(INVALID_SID), to(INVALID_SID), type(TYPE_INFO) { }40AdcCommand::AdcCommand() : cmdInt(0), priority(PRIORITY_NORMAL), from(INVALID_SID), to(INVALID_SID), type(TYPE_INFO) { }
4141
42AdcCommand::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) {42AdcCommand::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) {
43 addParam(Util::toString(sev * 100 + err));43 addParam((sev == SEV_SUCCESS && err == SUCCESS) ? "000" : Util::toString(sev * 100 + err));
44 addParam(desc);44 addParam(desc);
45}45}
4646
4747
=== modified file 'adchpp/AdcCommand.h'
--- adchpp/AdcCommand.h 2014-04-11 18:47:46 +0000
+++ adchpp/AdcCommand.h 2014-05-01 19:31:53 +0000
@@ -36,6 +36,7 @@
36 };36 };
3737
38 enum Error {38 enum Error {
39 SUCCESS = 0,
39 ERROR_GENERIC = 0,40 ERROR_GENERIC = 0,
40 ERROR_HUB_GENERIC = 10,41 ERROR_HUB_GENERIC = 10,
41 ERROR_HUB_FULL = 11,42 ERROR_HUB_FULL = 11,
@@ -63,7 +64,8 @@
63 ERROR_FILE_NOT_AVAILABLE = 51,64 ERROR_FILE_NOT_AVAILABLE = 51,
64 ERROR_FILE_PART_NOT_AVAILABLE = 52,65 ERROR_FILE_PART_NOT_AVAILABLE = 52,
65 ERROR_SLOTS_FULL = 53,66 ERROR_SLOTS_FULL = 53,
66 ERROR_NO_CLIENT_HASH = 5467 ERROR_NO_CLIENT_HASH = 54,
68 ERROR_HBRI_TIMEOUT = 55
67 };69 };
6870
69 enum Severity {71 enum Severity {
@@ -109,6 +111,7 @@
109 C(CMD, 'C','M','D');111 C(CMD, 'C','M','D');
110 C(NAT, 'N','A','T');112 C(NAT, 'N','A','T');
111 C(RNT, 'R','N','T');113 C(RNT, 'R','N','T');
114 C(TCP, 'T','C','P');
112#undef C115#undef C
113116
114 static const uint32_t HUB_SID = static_cast<uint32_t>(-1);117 static const uint32_t HUB_SID = static_cast<uint32_t>(-1);
@@ -225,6 +228,7 @@
225 C(CMD);228 C(CMD);
226 C(NAT);229 C(NAT);
227 C(RNT);230 C(RNT);
231 C(TCP);
228 default:232 default:
229 dcdebug("Unknown ADC command: %.50s\n", cmd.toString().c_str());233 dcdebug("Unknown ADC command: %.50s\n", cmd.toString().c_str());
230 return true;234 return true;
231235
=== modified file 'adchpp/Client.h'
--- adchpp/Client.h 2014-04-11 18:47:46 +0000
+++ adchpp/Client.h 2014-05-01 19:31:53 +0000
@@ -43,6 +43,8 @@
43 /** @param reason The statistic to update */43 /** @param reason The statistic to update */
44 ADCHPP_DLL virtual void disconnect(Util::Reason reason, const std::string &info = Util::emptyString) throw();44 ADCHPP_DLL virtual void disconnect(Util::Reason reason, const std::string &info = Util::emptyString) throw();
45 const std::string& getIp() const throw() { return socket->getIp(); }45 const std::string& getIp() const throw() { return socket->getIp(); }
46 bool getHbriParams(AdcCommand& cmd) const throw() { return socket->getHbriParams(cmd); }
47 bool isV6() const { return socket->isV6(); }
4648
47 /**49 /**
48 * Set data mode for aBytes bytes.50 * Set data mode for aBytes bytes.
4951
=== modified file 'adchpp/ClientManager.cpp'
--- adchpp/ClientManager.cpp 2014-04-11 18:47:46 +0000
+++ adchpp/ClientManager.cpp 2014-05-01 19:31:53 +0000
@@ -20,6 +20,7 @@
2020
21#include "ClientManager.h"21#include "ClientManager.h"
2222
23#include "Core.h"
23#include "File.h"24#include "File.h"
24#include "Client.h"25#include "Client.h"
25#include "LogManager.h"26#include "LogManager.h"
@@ -33,6 +34,15 @@
33#include <boost/asio/ip/address_v6.hpp>34#include <boost/asio/ip/address_v6.hpp>
34#include <boost/locale.hpp>35#include <boost/locale.hpp>
3536
37#include <boost/range/algorithm/find.hpp>
38#include <boost/range/algorithm/find_if.hpp>
39#include <boost/range/algorithm/remove_if.hpp>
40#include <boost/range/adaptor/map.hpp>
41
42using boost::adaptors::map_values;
43using boost::range::find;
44using boost::range::find_if;
45
36namespace adchpp {46namespace adchpp {
3747
38using namespace std;48using namespace std;
@@ -43,10 +53,52 @@
43core(core),53core(core),
44hub(*this),54hub(*this),
45maxCommandSize(16 * 1024),55maxCommandSize(16 * 1024),
46logTimeout(30 * 1000)56logTimeout(30 * 1000),
57hbriTimeout(5000)
47{58{
59 core.getSocketManager().addTimedJob(1000, std::bind(&ClientManager::onTimerSecond, this));
60}
61
62void ClientManager::prepareSupports(bool addHbri) {
48 hub.addSupports(AdcCommand::toFourCC("BASE"));63 hub.addSupports(AdcCommand::toFourCC("BASE"));
49 hub.addSupports(AdcCommand::toFourCC("TIGR"));64 hub.addSupports(AdcCommand::toFourCC("TIGR"));
65
66 if (addHbri)
67 hub.addSupports(AdcCommand::toFourCC("HBRI"));
68}
69
70void ClientManager::onTimerSecond() {
71 // HBRI
72 auto timeoutHbri = time::now() - time::millisec(hbriTimeout);
73 for (auto i = hbriTokens.begin(); i != hbriTokens.end();) {
74 if (timeoutHbri > i->second.second) {
75 auto cc = dynamic_cast<Client*>(i->second.first);
76 i = hbriTokens.erase(i);
77
78 dcdebug("ClientManager: HBRI timeout in state %d\n", cc->getState());
79
80 std::string proto = cc->isV6() ? "IPv4" : "IPv6";
81 AdcCommand sta(AdcCommand::SEV_RECOVERABLE, AdcCommand::ERROR_HBRI_TIMEOUT, proto + " validation timed out");
82 cc->send(sta);
83
84 cc->unsetFlag(Entity::FLAG_VALIDATE_HBRI);
85 cc->stripProtocolSupports();
86 if (cc->getState() == Entity::STATE_HBRI)
87 enterNormal(*cc, true, true);
88 } else {
89 i++;
90 }
91 }
92
93 // Logins
94 auto timeoutLogin = time::now() - time::millisec(getLogTimeout());
95 while (!logins.empty() && (timeoutLogin > logins.front().second)) {
96 auto cc = logins.front().first;
97
98 dcdebug("ClientManager: Login timeout in state %d\n", cc->getState());
99 cc->disconnect(Util::REASON_LOGIN_TIMEOUT);
100 logins.pop_front();
101 }
50}102}
51103
52Bot* ClientManager::createBot(const Bot::SendHandler& handler) {104Bot* ClientManager::createBot(const Bot::SendHandler& handler) {
@@ -149,16 +201,6 @@
149201
150void ClientManager::onConnected(Client& c) throw() {202void ClientManager::onConnected(Client& c) throw() {
151 dcdebug("%s connected\n", AdcCommand::fromSID(c.getSID()).c_str());203 dcdebug("%s connected\n", AdcCommand::fromSID(c.getSID()).c_str());
152 // First let's check if any clients have passed the login timeout...
153 auto timeout = time::now() - time::millisec(getLogTimeout());
154
155 while(!logins.empty() && (timeout > logins.front().second)) {
156 Client* cc = logins.front().first;
157
158 dcdebug("ClientManager: Login timeout in state %d\n", cc->getState());
159 cc->disconnect(Util::REASON_LOGIN_TIMEOUT);
160 logins.pop_front();
161 }
162204
163 logins.push_back(make_pair(&c, time::now()));205 logins.push_back(make_pair(&c, time::now()));
164206
@@ -225,6 +267,7 @@
225 badState(c, cmd);267 badState(c, cmd);
226 return false;268 return false;
227 }269 }
270
228 return true;271 return true;
229}272}
230273
@@ -245,26 +288,32 @@
245}288}
246289
247bool ClientManager::verifyINF(Entity& c, AdcCommand& cmd) throw() {290bool ClientManager::verifyINF(Entity& c, AdcCommand& cmd) throw() {
291 if (!verifyCID(c, cmd))
292 return false;
293
294 if (!verifyNick(c, cmd))
295 return false;
296
297 if (cmd.getParam("DE", 0, strtmp)) {
298 if (!Util::validateCharset(strtmp, 32)) {
299 disconnect(c, Util::REASON_INVALID_DESCRIPTION, "Invalid character in description");
300 return false;
301 }
302 }
303
248 Client* cc = dynamic_cast<Client*>(&c);304 Client* cc = dynamic_cast<Client*>(&c);
249305
250 if(cc) {306 if(cc) {
251 if(!verifyIp(*cc, cmd))307 if(!verifyIp(*cc, cmd, false))
252 return false;308 return false;
253 }309 }
254310
255 if(!verifyCID(c, cmd))
256 return false;
257
258 if(!verifyNick(c, cmd))
259 return false;
260
261 if(cmd.getParam("DE", 0, strtmp)) {
262 if(!Util::validateCharset(strtmp, 32)) {
263 disconnect(c, Util::REASON_INVALID_DESCRIPTION, "Invalid character in description");
264 return false;
265 }
266 }
267 c.updateFields(cmd);311 c.updateFields(cmd);
312
313 string tmp;
314 if (cmd.getParam("SU", 0, tmp) && !c.isSet(Entity::FLAG_VALIDATE_HBRI) && c.getState() != Entity::STATE_HBRI)
315 c.stripProtocolSupports();
316
268 return true;317 return true;
269}318}
270319
@@ -307,13 +356,35 @@
307 }356 }
308357
309 if(overflowing > 3 && overflowing > (entities.size() / 4)) {358 if(overflowing > 3 && overflowing > (entities.size() / 4)) {
310 disconnect(c, Util::REASON_NO_BANDWIDTH, "Not enough bandwidth available, please try again later", AdcCommand::ERROR_HUB_FULL);359 disconnect(c, Util::REASON_NO_BANDWIDTH, "Not enough bandwidth available, please try again later", AdcCommand::ERROR_HUB_FULL, Util::emptyString, 1);
311 return false;360 return false;
312 }361 }
313362
314 return true;363 return true;
315}364}
316365
366bool ClientManager::sendHBRI(Entity& c) {
367 if (c.hasSupport(AdcCommand::toFourCC("HBRI"))) {
368 AdcCommand cmd(AdcCommand::CMD_TCP);
369 if (!dynamic_cast<Client*>(&c)->getHbriParams(cmd)) {
370 return false;
371 }
372
373 c.setFlag(Entity::FLAG_VALIDATE_HBRI);
374 if (c.getState() != Entity::STATE_NORMAL)
375 c.setState(Entity::STATE_HBRI);
376
377 auto token = Util::toString(Util::rand());
378 hbriTokens.insert(make_pair(token, make_pair(&c, time::now())));
379
380 cmd.addParam("TO", token);
381 c.send(cmd);
382 return true;
383 }
384
385 return false;
386}
387
317bool ClientManager::handle(AdcCommand::INF, Entity& c, AdcCommand& cmd) throw() {388bool ClientManager::handle(AdcCommand::INF, Entity& c, AdcCommand& cmd) throw() {
318 if(c.getState() != Entity::STATE_IDENTIFY && c.getState() != Entity::STATE_NORMAL) {389 if(c.getState() != Entity::STATE_IDENTIFY && c.getState() != Entity::STATE_NORMAL) {
319 badState(c, cmd);390 badState(c, cmd);
@@ -335,23 +406,98 @@
335 return true;406 return true;
336}407}
337408
338bool ClientManager::verifyIp(Client& c, AdcCommand& cmd) throw() {409static const int allowedCount = 3;
410static const char* allowedV4[allowedCount] = { "I4", "U4", "SU" };
411static const char* allowedV6[allowedCount] = { "I6", "U6", "SU" };
412bool ClientManager::handle(AdcCommand::TCP, Entity& c, AdcCommand& cmd) throw() {
413 dcdebug("Received HBRI TCP: %s", cmd.toString().c_str());
414
415 string error;
416 string token;
417 if(cmd.getParam("TO", 0, token)) {
418 auto p = hbriTokens.find(token);
419 if (p != hbriTokens.end()) {
420 Client* mainCC = dynamic_cast<Client*>(p->second.first);
421 mainCC->unsetFlag(Entity::FLAG_VALIDATE_HBRI);
422
423 if (mainCC->getState() != Entity::STATE_HBRI && mainCC->getState() != Entity::STATE_NORMAL) {
424 badState(c, cmd);
425 return false;
426 }
427
428 hbriTokens.erase(p);
429
430 if (!verifyIp(*dynamic_cast<Client*>(&c), cmd, true))
431 return false;
432
433 // disconnect the validation connection
434 AdcCommand sta(AdcCommand::SEV_SUCCESS, AdcCommand::SUCCESS, "Validation succeed");
435 c.send(sta);
436 c.disconnect(Util::REASON_HBRI);
437
438 // remove extra parameters
439 auto& params = cmd.getParameters();
440 const auto& allowed = dynamic_cast<Client*>(&c)->isV6() ? allowedV6 : allowedV4;
441
442 params.erase(boost::remove_if(params, [&](const string& s) {
443 return find(allowed, allowed + allowedCount, s.substr(0, 2)) == &allowed[allowedCount];
444 }), params.end());
445
446 // update the fields for the main entity
447 mainCC->updateFields(cmd);
448
449 if (mainCC->getState() == Entity::STATE_HBRI) {
450 // continue with the normal login
451 enterNormal(*mainCC, true, true);
452 } else {
453 // send the updated fields
454 AdcCommand inf(AdcCommand::CMD_INF, AdcCommand::TYPE_BROADCAST, mainCC->getSID());
455 inf.getParameters() = cmd.getParameters();
456 sendToAll(inf.getBuffer());
457 }
458 return true;
459 } else {
460 error = "Unknown validation token";
461 }
462 } else {
463 error = "Validation token missing";
464 }
465
466 dcassert(!error.empty());
467 AdcCommand sta(AdcCommand::SEV_FATAL, AdcCommand::ERROR_LOGIN_GENERIC, error);
468 c.send(sta);
469
470 c.disconnect(Util::REASON_HBRI);
471 return true;
472}
473
474bool ClientManager::verifyIp(Client& c, AdcCommand& cmd, bool isHbriConn) throw() {
339 if(c.isSet(Entity::FLAG_OK_IP))475 if(c.isSet(Entity::FLAG_OK_IP))
340 return true;476 return true;
341477
342 using namespace boost::asio::ip;478 using namespace boost::asio::ip;
343479
344 auto remote = address::from_string(c.getIp());480 address remote;
481
482 try {
483 remote = address::from_string(c.getIp());
484 } catch(const boost::system::system_error&) {
485 printf("Error when reading IP %s\n", c.getIp().c_str());
486 return false;
487 }
488
345 std::string ip;489 std::string ip;
346490
347 if(remote.is_v4() || (remote.is_v6() && remote.to_v6().is_v4_mapped())) {491 bool doValidation = false;
492 if (!c.isV6()) {
348 auto v4 = remote.is_v4() ? remote.to_v4() : remote.to_v6().to_v4();493 auto v4 = remote.is_v4() ? remote.to_v4() : remote.to_v6().to_v4();
349494
350 if(cmd.getParam("I4", 0, ip)) {495 if(cmd.getParam("I4", 0, ip)) {
351 dcdebug("%s verifying IP %s\n", AdcCommand::fromSID(c.getSID()).c_str(), ip.c_str());496 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()) {497 if(ip.empty() || address_v4::from_string(ip) == address_v4::any()) {
353 cmd.delParam("I4", 0);498 cmd.delParam("I4", 0);
354 } else if(address_v4::from_string(ip) != v4 && !Util::isPrivateIp(c.getIp())) {499 cmd.addParam("I4", c.getIp());
500 } else if(address_v4::from_string(ip) != v4 && !Util::isPrivateIp(c.getIp(), false)) {
355 disconnect(c, Util::REASON_INVALID_IP, "Your IP is " + c.getIp() +501 disconnect(c, Util::REASON_INVALID_IP, "Your IP is " + c.getIp() +
356 ", reconfigure your client settings", AdcCommand::ERROR_BAD_IP, "IP" + c.getIp());502 ", reconfigure your client settings", AdcCommand::ERROR_BAD_IP, "IP" + c.getIp());
357 return false;503 return false;
@@ -360,21 +506,24 @@
360 }506 }
361 }507 }
362508
363 if(!c.hasField("I4")) {509 if (!isHbriConn) {
364 c.setField("I4", v4.to_string());510 if(!c.hasField("I4")) {
365 }511 c.setField("I4", v4.to_string());
366512 }
367 if(c.getState() != Entity::STATE_NORMAL) {513
368 cmd.addParam("I4", v4.to_string());514 string tmp;
369 }515 doValidation = cmd.getParam("I6", 0, tmp) && !tmp.empty();
370516 }
371 cmd.delParam("I6", 0); // We can't check this so we remove it instead...fix?517
372 } else if(remote.is_v6()) {518 cmd.delParam("U6", 0);
519 cmd.delParam("I6", 0);
520 } else {
373 if(cmd.getParam("I6", 0, ip)) {521 if(cmd.getParam("I6", 0, ip)) {
374 dcdebug("%s verifying IPv6 %s\n", AdcCommand::fromSID(c.getSID()).c_str(), ip.c_str());522 dcdebug("%s verifying IPv6 %s\n", AdcCommand::fromSID(c.getSID()).c_str(), ip.c_str());
375 if(ip.empty() || address_v6::from_string(ip) == address_v6::any()) {523 if(ip.empty() || address_v6::from_string(ip) == address_v6::any()) {
376 cmd.delParam("I6", 0);524 cmd.delParam("I6", 0);
377 } else if(address_v6::from_string(ip) != remote.to_v6() && !Util::isPrivateIp(c.getIp())) {525 cmd.addParam("I6", c.getIp());
526 } else if(address_v6::from_string(ip) != remote.to_v6() && !Util::isPrivateIp(c.getIp(), true)) {
378 disconnect(c, Util::REASON_INVALID_IP, "Your IP is " + c.getIp() +527 disconnect(c, Util::REASON_INVALID_IP, "Your IP is " + c.getIp() +
379 ", reconfigure your client settings", AdcCommand::ERROR_BAD_IP, "IP" + c.getIp());528 ", reconfigure your client settings", AdcCommand::ERROR_BAD_IP, "IP" + c.getIp());
380 return false;529 return false;
@@ -383,15 +532,25 @@
383 }532 }
384 }533 }
385534
386 if(!c.hasField("I6")) {535 if (!isHbriConn) {
387 c.setField("I6", c.getIp());536 if (!c.hasField("I6")) {
388 }537 c.setField("I6", c.getIp());
389538 }
390 if(c.getState() != Entity::STATE_NORMAL) {539
391 cmd.addParam("I6", c.getIp());540 string tmp;
392 }541 doValidation = cmd.getParam("I4", 0, tmp) && !tmp.empty();
393542 }
394 cmd.delParam("I4", 0); // We can't check this so we remove it instead...fix?543
544 cmd.delParam("I4", 0);
545 cmd.delParam("U4", 0);
546 }
547
548 if (doValidation) {
549 if (c.getState() == Entity::STATE_NORMAL) {
550 sendHBRI(c);
551 } else {
552 c.setFlag(Entity::FLAG_VALIDATE_HBRI);
553 }
395 }554 }
396555
397 return true;556 return true;
@@ -516,7 +675,7 @@
516 signalState_(c, oldState);675 signalState_(c, oldState);
517}676}
518677
519void ClientManager::disconnect(Entity& c, Util::Reason reason, const std::string& info, AdcCommand::Error error, const std::string& staParam) {678void ClientManager::disconnect(Entity& c, Util::Reason reason, const std::string& info, AdcCommand::Error error, const std::string& staParam, int aReconnectTime) {
520 // send a fatal STA679 // send a fatal STA
521 AdcCommand sta(AdcCommand::SEV_FATAL, error, info);680 AdcCommand sta(AdcCommand::SEV_FATAL, error, info);
522 if(!staParam.empty())681 if(!staParam.empty())
@@ -525,7 +684,7 @@
525684
526 // send a QUI685 // send a QUI
527 c.send(AdcCommand(AdcCommand::CMD_QUI).addParam(AdcCommand::fromSID(c.getSID()))686 c.send(AdcCommand(AdcCommand::CMD_QUI).addParam(AdcCommand::fromSID(c.getSID()))
528 .addParam("DI", "1").addParam("MS", info).addParam("TL", "-1"));687 .addParam("DI", "1").addParam("MS", info).addParam("TL", Util::toString(aReconnectTime)));
529688
530 c.disconnect(reason);689 c.disconnect(reason);
531}690}
@@ -562,6 +721,14 @@
562}721}
563722
564bool ClientManager::enterNormal(Entity& c, bool sendData, bool sendOwnInf) throw() {723bool ClientManager::enterNormal(Entity& c, bool sendData, bool sendOwnInf) throw() {
724 if (c.isSet(Entity::FLAG_VALIDATE_HBRI)) {
725 if (sendHBRI(c)) {
726 return false;
727 }
728
729 c.unsetFlag(Entity::FLAG_VALIDATE_HBRI);
730 }
731
565 dcassert(c.getState() == Entity::STATE_IDENTIFY || c.getState() == Entity::STATE_VERIFY);732 dcassert(c.getState() == Entity::STATE_IDENTIFY || c.getState() == Entity::STATE_VERIFY);
566 dcdebug("%s entering NORMAL\n", AdcCommand::fromSID(c.getSID()).c_str());733 dcdebug("%s entering NORMAL\n", AdcCommand::fromSID(c.getSID()).c_str());
567734
@@ -596,6 +763,13 @@
596 if(i != logins.end()) {763 if(i != logins.end()) {
597 logins.erase(i);764 logins.erase(i);
598 }765 }
766
767 if (e.hasSupport(AdcCommand::toFourCC("HBRI"))) {
768 auto i = find_if(hbriTokens | map_values, CompareFirst<Entity*, time::ptime>(c)).base();
769 if (i != hbriTokens.end()) {
770 hbriTokens.erase(i);
771 }
772 }
599}773}
600774
601void ClientManager::removeEntity(Entity& c, Util::Reason reason, const std::string &info) throw() {775void ClientManager::removeEntity(Entity& c, Util::Reason reason, const std::string &info) throw() {
@@ -644,4 +818,4 @@
644 removeEntity(c, reason, info);818 removeEntity(c, reason, info);
645}819}
646820
647}821}
648\ No newline at end of file822\ No newline at end of file
649823
=== modified file 'adchpp/ClientManager.h'
--- adchpp/ClientManager.h 2014-04-11 18:47:46 +0000
+++ adchpp/ClientManager.h 2014-05-01 19:31:53 +0000
@@ -131,7 +131,7 @@
131 /**131 /**
132 * Verify that IP is correct and replace any zero addresses.132 * Verify that IP is correct and replace any zero addresses.
133 */133 */
134 ADCHPP_DLL bool verifyIp(Client& c, AdcCommand& cmd) throw();134 ADCHPP_DLL bool verifyIp(Client& c, AdcCommand& cmd, bool isHbriConn) throw();
135135
136 /**136 /**
137 * Verify that CID is correct and corresponds to PID137 * Verify that CID is correct and corresponds to PID
@@ -169,10 +169,13 @@
169 void setMaxCommandSize(size_t newSize) { maxCommandSize = newSize; }169 void setMaxCommandSize(size_t newSize) { maxCommandSize = newSize; }
170 size_t getMaxCommandSize() const { return maxCommandSize; }170 size_t getMaxCommandSize() const { return maxCommandSize; }
171171
172 void setHbriTimeout(size_t millis) { hbriTimeout = millis; }
173 size_t getHbriTimeout() const { return hbriTimeout; }
172 void setLogTimeout(size_t millis) { logTimeout = millis; }174 void setLogTimeout(size_t millis) { logTimeout = millis; }
173 size_t getLogTimeout() const { return logTimeout; }175 size_t getLogTimeout() const { return logTimeout; }
174176
175 Core &getCore() const { return core; }177 Core &getCore() const { return core; }
178 void prepareSupports(bool addHbri);
176private:179private:
177 friend class Core;180 friend class Core;
178 friend class Client;181 friend class Client;
@@ -183,6 +186,9 @@
183186
184 std::list<std::pair<Client*, time::ptime> > logins;187 std::list<std::pair<Client*, time::ptime> > logins;
185188
189 typedef std::unordered_map<std::string, std::pair<Entity*, time::ptime>> TokenMap;
190 TokenMap hbriTokens;
191
186 EntityMap entities;192 EntityMap entities;
187 typedef std::unordered_map<std::string, Entity*> NickMap;193 typedef std::unordered_map<std::string, Entity*> NickMap;
188 NickMap nicks;194 NickMap nicks;
@@ -193,6 +199,7 @@
193199
194 size_t maxCommandSize;200 size_t maxCommandSize;
195 size_t logTimeout;201 size_t logTimeout;
202 size_t hbriTimeout;
196203
197 // Temporary string to use whenever a temporary string is needed (to avoid (de)allocating memory all the time...)204 // Temporary string to use whenever a temporary string is needed (to avoid (de)allocating memory all the time...)
198 std::string strtmp;205 std::string strtmp;
@@ -203,6 +210,7 @@
203210
204 uint32_t makeSID();211 uint32_t makeSID();
205212
213 bool sendHBRI(Entity& c);
206 void maybeSend(Entity& c, const AdcCommand& cmd);214 void maybeSend(Entity& c, const AdcCommand& cmd);
207215
208 void removeLogins(Entity& c) throw();216 void removeLogins(Entity& c) throw();
@@ -210,6 +218,7 @@
210218
211 bool handle(AdcCommand::SUP, Entity& c, AdcCommand& cmd) throw();219 bool handle(AdcCommand::SUP, Entity& c, AdcCommand& cmd) throw();
212 bool handle(AdcCommand::INF, Entity& c, AdcCommand& cmd) throw();220 bool handle(AdcCommand::INF, Entity& c, AdcCommand& cmd) throw();
221 bool handle(AdcCommand::TCP, Entity& c, AdcCommand& cmd) throw();
213 bool handleDefault(Entity& c, AdcCommand& cmd) throw();222 bool handleDefault(Entity& c, AdcCommand& cmd) throw();
214223
215 template<typename T> bool handle(T, Entity& c, AdcCommand& cmd) throw() { return handleDefault(c, cmd); }224 template<typename T> bool handle(T, Entity& c, AdcCommand& cmd) throw() { return handleDefault(c, cmd); }
@@ -225,7 +234,7 @@
225 void badState(Entity& c, const AdcCommand& cmd) throw();234 void badState(Entity& c, const AdcCommand& cmd) throw();
226 /** send a fatal STA, a QUI with TL-1, then disconnect. */235 /** send a fatal STA, a QUI with TL-1, then disconnect. */
227 void disconnect(Entity& c, Util::Reason reason, const std::string& info,236 void disconnect(Entity& c, Util::Reason reason, const std::string& info,
228 AdcCommand::Error error = AdcCommand::ERROR_PROTOCOL_GENERIC, const std::string& staParam = Util::emptyString);237 AdcCommand::Error error = AdcCommand::ERROR_PROTOCOL_GENERIC, const std::string& staParam = Util::emptyString, int aReconnectTime = -1);
229238
230 SignalConnected::Signal signalConnected_;239 SignalConnected::Signal signalConnected_;
231 SignalReady::Signal signalReady_;240 SignalReady::Signal signalReady_;
@@ -236,6 +245,7 @@
236 SignalDisconnected::Signal signalDisconnected_;245 SignalDisconnected::Signal signalDisconnected_;
237246
238 ClientManager(Core &core) throw();247 ClientManager(Core &core) throw();
248 void onTimerSecond();
239};249};
240250
241}251}
242252
=== modified file 'adchpp/Entity.cpp'
--- adchpp/Entity.cpp 2014-04-11 18:47:46 +0000
+++ adchpp/Entity.cpp 2014-05-01 19:31:53 +0000
@@ -48,10 +48,9 @@
4848
49 if(code == AdcCommand::toField("SU")) {49 if(code == AdcCommand::toField("SU")) {
50 filters.clear();50 filters.clear();
5151 if ((value.size() + 1) % 5 == 0) {
52 if((value.size() + 1) % 5 == 0) {
53 filters.reserve((value.size() + 1) / 5);52 filters.reserve((value.size() + 1) / 5);
54 for(size_t i = 0; i < value.size(); i += 5) {53 for (size_t i = 0; i < value.size(); i += 5) {
55 filters.push_back(AdcCommand::toFourCC(value.data() + i));54 filters.push_back(AdcCommand::toFourCC(value.data() + i));
56 }55 }
57 }56 }
@@ -154,6 +153,41 @@
154 }153 }
155}154}
156155
156bool Entity::hasClientSupport(uint32_t feature) const {
157 return std::find(filters.begin(), filters.end(), feature) != filters.end();
158}
159
160bool Entity::removeClientSupport(uint32_t feature) {
161 auto f = std::find(filters.begin(), filters.end(), feature);
162 if (f == filters.end()) {
163 return false;
164 }
165
166 filters.erase(f);
167
168 auto& supports = fields.find(AdcCommand::toField("SU"))->second;
169
170 auto p = supports.find(AdcCommand::fromFourCC(feature));
171 dcassert(p != std::string::npos);
172 supports.erase(p, 5);
173
174 if (!supports.empty() && supports.back() == ',')
175 supports.erase(supports.size() - 1);
176
177 return true;
178}
179
180static const int protoSupportCount = 2;
181static uint32_t supports4[protoSupportCount] = { AdcCommand::toFourCC("TCP4"), AdcCommand::toFourCC("UDP4") };
182static uint32_t supports6[protoSupportCount] = { AdcCommand::toFourCC("TCP6"), AdcCommand::toFourCC("UDP6") };
183
184void Entity::stripProtocolSupports() throw() {
185 const auto& sup = dynamic_cast<Client*>(this)->isV6() ? supports4 : supports6;
186 for (auto i = 0; i < protoSupportCount; ++i) {
187 removeClientSupport(sup[i]);
188 }
189}
190
157bool Entity::isFiltered(const std::string& features) const {191bool Entity::isFiltered(const std::string& features) const {
158 if(filters.empty()) {192 if(filters.empty()) {
159 return true;193 return true;
160194
=== modified file 'adchpp/Entity.h'
--- adchpp/Entity.h 2014-04-11 18:47:46 +0000
+++ adchpp/Entity.h 2014-05-01 19:31:53 +0000
@@ -33,6 +33,8 @@
33 enum State {33 enum State {
34 /** Initial protocol negotiation (wait for SUP) */34 /** Initial protocol negotiation (wait for SUP) */
35 STATE_PROTOCOL,35 STATE_PROTOCOL,
36 /** Validating the secondary address */
37 STATE_HBRI,
36 /** Identify the connecting client (wait for INF) */38 /** Identify the connecting client (wait for INF) */
37 STATE_IDENTIFY,39 STATE_IDENTIFY,
38 /** Verify the client (wait for PAS) */40 /** Verify the client (wait for PAS) */
@@ -63,7 +65,10 @@
63 FLAG_OK_IP = 0x400,65 FLAG_OK_IP = 0x400,
6466
65 /** This entity is now a ghost being disconnected, totally ignored by ADCH++ */67 /** This entity is now a ghost being disconnected, totally ignored by ADCH++ */
66 FLAG_GHOST = 0x80068 FLAG_GHOST = 0x800,
69
70 /** Set in the login phase if the users provides an IP for another protocol **/
71 FLAG_VALIDATE_HBRI = 0x1000
67 };72 };
6873
6974
@@ -87,6 +92,12 @@
87 ADCHPP_DLL bool hasSupport(uint32_t feature) const;92 ADCHPP_DLL bool hasSupport(uint32_t feature) const;
88 ADCHPP_DLL bool removeSupports(uint32_t feature);93 ADCHPP_DLL bool removeSupports(uint32_t feature);
8994
95 ADCHPP_DLL bool hasClientSupport(uint32_t feature) const;
96 ADCHPP_DLL bool removeClientSupport(uint32_t feature);
97
98 /** Remove supports for the protocol that wasn't used for connecting **/
99 ADCHPP_DLL void stripProtocolSupports() throw();
100
90 ADCHPP_DLL const BufferPtr& getSUP() const;101 ADCHPP_DLL const BufferPtr& getSUP() const;
91102
92 uint32_t getSID() const { return sid; }103 uint32_t getSID() const { return sid; }
93104
=== modified file 'adchpp/ManagedSocket.cpp'
--- adchpp/ManagedSocket.cpp 2014-04-11 18:47:46 +0000
+++ adchpp/ManagedSocket.cpp 2014-05-01 19:31:53 +0000
@@ -22,18 +22,21 @@
2222
23#include "SocketManager.h"23#include "SocketManager.h"
2424
25#include <boost/asio/ip/address.hpp>
26
25namespace adchpp {27namespace adchpp {
2628
27using namespace std;29using namespace std;
2830
29using namespace boost::asio;31using namespace boost::asio;
3032
31ManagedSocket::ManagedSocket(SocketManager &sm, const AsyncStreamPtr &sock_) :33ManagedSocket::ManagedSocket(SocketManager &sm, const AsyncStreamPtr &sock_, const ServerInfoPtr& aServer) :
32 sock(sock_),34 sock(sock_),
33 overflow(time::not_a_date_time),35 overflow(time::not_a_date_time),
34 disc(time::not_a_date_time),36 disc(time::not_a_date_time),
35 lastWrite(time::not_a_date_time),37 lastWrite(time::not_a_date_time),
36 sm(sm)38 sm(sm),
39 server(aServer)
37{ }40{ }
3841
39ManagedSocket::~ManagedSocket() throw() {42ManagedSocket::~ManagedSocket() throw() {
@@ -251,6 +254,39 @@
251 std::string info;254 std::string info;
252};255};
253256
257bool ManagedSocket::getHbriParams(AdcCommand& cmd) const throw() {
258 if (!isV6()) {
259 if (!server->address6.empty()) {
260 cmd.addParam("I6", server->address6);
261 } else {
262 return false;
263 }
264
265 cmd.addParam("P6", server->port);
266 } else {
267 if (!server->address4.empty()) {
268 cmd.addParam("I4", server->address4);
269 } else {
270 return false;
271 }
272
273 cmd.addParam("P4", server->port);
274 }
275
276 return true;
277}
278
279bool ManagedSocket::isV6() const throw() {
280 using namespace boost::asio::ip;
281
282 address remote;
283 remote = address::from_string(ip);
284 if (remote.is_v4() || (remote.is_v6() && remote.to_v6().is_v4_mapped()))
285 return false;
286
287 return true;
288}
289
254void ManagedSocket::disconnect(Util::Reason reason, const std::string &info) throw() {290void ManagedSocket::disconnect(Util::Reason reason, const std::string &info) throw() {
255 if(disconnecting()) {291 if(disconnecting()) {
256 return;292 return;
257293
=== modified file 'adchpp/ManagedSocket.h'
--- adchpp/ManagedSocket.h 2014-04-11 18:47:46 +0000
+++ adchpp/ManagedSocket.h 2014-05-01 19:31:53 +0000
@@ -22,6 +22,8 @@
22#include "common.h"22#include "common.h"
2323
24#include "forward.h"24#include "forward.h"
25
26#include "AdcCommand.h"
25#include "Signal.h"27#include "Signal.h"
26#include "Util.h"28#include "Util.h"
27#include "Buffer.h"29#include "Buffer.h"
@@ -35,7 +37,7 @@
35 */37 */
36class ManagedSocket : private boost::noncopyable, public enable_shared_from_this<ManagedSocket> {38class ManagedSocket : private boost::noncopyable, public enable_shared_from_this<ManagedSocket> {
37public:39public:
38 ManagedSocket(SocketManager &sm, const AsyncStreamPtr& sock_);40 ManagedSocket(SocketManager &sm, const AsyncStreamPtr& sock_, const ServerInfoPtr& aServer);
3941
40 /** Asynchronous write */42 /** Asynchronous write */
41 ADCHPP_DLL void write(const BufferPtr& buf, bool lowPrio = false) throw();43 ADCHPP_DLL void write(const BufferPtr& buf, bool lowPrio = false) throw();
@@ -68,6 +70,8 @@
6870
69 ~ManagedSocket() throw();71 ~ManagedSocket() throw();
7072
73 bool getHbriParams(AdcCommand& cmd) const throw();
74 bool isV6() const throw();
71private:75private:
72 friend class SocketManager;76 friend class SocketManager;
73 friend class SocketFactory;77 friend class SocketFactory;
@@ -110,6 +114,8 @@
110 FailedHandler failedHandler;114 FailedHandler failedHandler;
111115
112 SocketManager &sm;116 SocketManager &sm;
117
118 ServerInfoPtr server;
113};119};
114120
115}121}
116122
=== modified file 'adchpp/ServerInfo.h'
--- adchpp/ServerInfo.h 2014-04-11 18:47:46 +0000
+++ adchpp/ServerInfo.h 2014-05-01 19:31:53 +0000
@@ -22,7 +22,10 @@
22namespace adchpp {22namespace adchpp {
2323
24struct ServerInfo {24struct ServerInfo {
25 std::string ip;25 std::string bind4;
26 std::string bind6;
27 std::string address4;
28 std::string address6;
26 std::string port;29 std::string port;
2730
28 struct TLSInfo {31 struct TLSInfo {
2932
=== modified file 'adchpp/SocketManager.cpp'
--- adchpp/SocketManager.cpp 2014-04-11 18:47:46 +0000
+++ adchpp/SocketManager.cpp 2014-05-01 19:31:53 +0000
@@ -20,6 +20,7 @@
2020
21#include "SocketManager.h"21#include "SocketManager.h"
2222
23#include "ClientManager.h"
23#include "LogManager.h"24#include "LogManager.h"
24#include "ManagedSocket.h"25#include "ManagedSocket.h"
25#include "ServerInfo.h"26#include "ServerInfo.h"
@@ -47,7 +48,9 @@
47bufferSize(1024),48bufferSize(1024),
48maxBufferSize(16 * 1024),49maxBufferSize(16 * 1024),
49overflowTimeout(60 * 1000),50overflowTimeout(60 * 1000),
50disconnectTimeout(10 * 1000)51disconnectTimeout(10 * 1000),
52hasV4Address(false),
53hasV6Address(false)
51{54{
52}55}
5356
@@ -192,10 +195,11 @@
192195
193class SocketFactory : public enable_shared_from_this<SocketFactory>, boost::noncopyable {196class SocketFactory : public enable_shared_from_this<SocketFactory>, boost::noncopyable {
194public:197public:
195 SocketFactory(SocketManager& sm, const SocketManager::IncomingHandler& handler_, const ServerInfo& info, const ip::tcp::endpoint& endpoint) :198 SocketFactory(SocketManager& sm, const SocketManager::IncomingHandler& handler_, ServerInfoPtr& info, const ip::tcp::endpoint& endpoint) :
196 sm(sm),199 sm(sm),
197 acceptor(sm.io),200 acceptor(sm.io),
198 handler(handler_)201 handler(handler_),
202 si(info)
199 {203 {
200 acceptor.open(endpoint.protocol());204 acceptor.open(endpoint.protocol());
201 acceptor.set_option(socket_base::reuse_address(true));205 acceptor.set_option(socket_base::reuse_address(true));
@@ -203,21 +207,23 @@
203 acceptor.set_option(ip::v6_only(true));207 acceptor.set_option(ip::v6_only(true));
204 }208 }
205209
210 auto a = endpoint.address().to_string();
211
206 acceptor.bind(endpoint);212 acceptor.bind(endpoint);
207 acceptor.listen(socket_base::max_connections);213 acceptor.listen(socket_base::max_connections);
208214
209 LOGC(sm.getCore(), SocketManager::className,215 LOGC(sm.getCore(), SocketManager::className,
210 "Listening on " + formatEndpoint(endpoint) +216 "Listening on " + formatEndpoint(endpoint) +
211 " (Encrypted: " + (info.secure() ? "Yes)" : "No)"));217 " (Encrypted: " + (info->secure() ? "Yes)" : "No)"));
212218
213#ifdef HAVE_OPENSSL219#ifdef HAVE_OPENSSL
214 if(info.secure()) {220 if(info->secure()) {
215 context.reset(new ssl::context(sm.io, ssl::context::tlsv1_server));221 context.reset(new ssl::context(sm.io, ssl::context::tlsv1_server));
216 context->set_options(ssl::context::no_sslv2 | ssl::context::no_sslv3 | ssl::context::single_dh_use);222 context->set_options(ssl::context::no_sslv2 | ssl::context::no_sslv3 | ssl::context::single_dh_use);
217 //context->set_password_callback(boost::bind(&server::get_password, this));223 //context->set_password_callback(boost::bind(&server::get_password, this));
218 context->use_certificate_chain_file(info.TLSParams.cert);224 context->use_certificate_chain_file(info->TLSParams.cert);
219 context->use_private_key_file(info.TLSParams.pkey, ssl::context::pem);225 context->use_private_key_file(info->TLSParams.pkey, ssl::context::pem);
220 context->use_tmp_dh_file(info.TLSParams.dh);226 context->use_tmp_dh_file(info->TLSParams.dh);
221 }227 }
222#endif228#endif
223 }229 }
@@ -230,12 +236,12 @@
230#ifdef HAVE_OPENSSL236#ifdef HAVE_OPENSSL
231 if(context) {237 if(context) {
232 auto s = make_shared<TLSSocketStream>(sm.io, *context);238 auto s = make_shared<TLSSocketStream>(sm.io, *context);
233 auto socket = make_shared<ManagedSocket>(sm, s);239 auto socket = make_shared<ManagedSocket>(sm, s, si);
234 acceptor.async_accept(s->sock.lowest_layer(), std::bind(&SocketFactory::handleAccept, shared_from_this(), std::placeholders::_1, socket));240 acceptor.async_accept(s->sock.lowest_layer(), std::bind(&SocketFactory::handleAccept, shared_from_this(), std::placeholders::_1, socket));
235 } else {241 } else {
236#endif242#endif
237 auto s = make_shared<SimpleSocketStream>(sm.io);243 auto s = make_shared<SimpleSocketStream>(sm.io);
238 auto socket = make_shared<ManagedSocket>(sm, s);244 auto socket = make_shared<ManagedSocket>(sm, s, si);
239 acceptor.async_accept(s->sock.lowest_layer(), std::bind(&SocketFactory::handleAccept, shared_from_this(), std::placeholders::_1, socket));245 acceptor.async_accept(s->sock.lowest_layer(), std::bind(&SocketFactory::handleAccept, shared_from_this(), std::placeholders::_1, socket));
240#ifdef HAVE_OPENSSL246#ifdef HAVE_OPENSSL
241 }247 }
@@ -245,7 +251,9 @@
245 void handleAccept(const error_code& ec, const ManagedSocketPtr& socket) {251 void handleAccept(const error_code& ec, const ManagedSocketPtr& socket) {
246 if(!ec) {252 if(!ec) {
247 socket->sock->setOptions(sm.getBufferSize());253 socket->sock->setOptions(sm.getBufferSize());
248 socket->setIp(socket->sock->getIp());254 auto ip = socket->sock->getIp();
255 auto p = ip.find("%");
256 socket->setIp(p != string::npos ? ip.substr(0, p) : ip);
249 }257 }
250258
251 completeAccept(ec, socket);259 completeAccept(ec, socket);
@@ -263,37 +271,68 @@
263 SocketManager &sm;271 SocketManager &sm;
264 ip::tcp::acceptor acceptor;272 ip::tcp::acceptor acceptor;
265 SocketManager::IncomingHandler handler;273 SocketManager::IncomingHandler handler;
266274 ServerInfoPtr si;
267#ifdef HAVE_OPENSSL275#ifdef HAVE_OPENSSL
268 unique_ptr<ssl::context> context;276 unique_ptr<ssl::context> context;
269#endif277#endif
270278
271};279};
272280
281void SocketManager::prepareProtocol(ServerInfoPtr& si, bool v6) {
282 const string proto = v6 ? "IPv6" : "IPv4";
283 try {
284 using ip::tcp;
285 tcp::resolver r(io);
286
287 // Resolve the public address
288 string& hubAddress = v6 ? si->address6 : si->address4;
289 if (!hubAddress.empty()) {
290 try {
291 auto remote = r.resolve(tcp::resolver::query(v6 ? tcp::v6() : tcp::v4(), hubAddress, si->port,
292 tcp::resolver::query::address_configured | tcp::resolver::query::passive));
293 hubAddress = remote->endpoint().address().to_string();
294 v6 ? hasV6Address = true : hasV4Address = true;
295 } catch (const std::exception& e) {
296 LOG(SocketManager::className, "Error when resolving the " + proto + " hub address " + hubAddress + ": " + e.what());
297 hubAddress = Util::emptyString;
298 }
299 }
300
301 // Resolve the bind address
302 auto local = r.resolve(tcp::resolver::query(v6 ? tcp::v6() : tcp::v4(), v6 ? si->bind6 : si->bind4, si->port,
303 tcp::resolver::query::address_configured | tcp::resolver::query::passive));
304
305 for (auto i = local; i != tcp::resolver::iterator(); ++i) {
306 auto factory = make_shared<SocketFactory>(*this, incomingHandler, si, *i);
307 factory->prepareAccept();
308 factories.push_back(factory);
309 }
310 } catch (const std::exception& e) {
311 LOG(SocketManager::className, "Error while loading " + proto + " server on port " + si->port + ": " + e.what());
312 }
313}
314
273int SocketManager::run() {315int SocketManager::run() {
316 //Sleep(10000);
274 LOG(SocketManager::className, "Starting");317 LOG(SocketManager::className, "Starting");
275318
276 work.reset(new io_service::work(io));319 work.reset(new io_service::work(io));
277320
278 for(auto i = servers.begin(), iend = servers.end(); i != iend; ++i) {321 for(auto i = servers.begin(), iend = servers.end(); i != iend; ++i) {
279 auto& si = *i;322 auto& si = *i;
280323 bool listenAll = si->bind4.empty() && si->bind6.empty();
281 try {324
282 using ip::tcp;325 if (!si->bind4.empty() || listenAll) {
283 tcp::resolver r(io);326 prepareProtocol(si, false);
284 auto local = r.resolve(tcp::resolver::query(si->ip, si->port,327 }
285 tcp::resolver::query::address_configured | tcp::resolver::query::passive));328
286329 if (!si->bind6.empty() || listenAll) {
287 for(auto i = local; i != tcp::resolver::iterator(); ++i) {330 prepareProtocol(si, true);
288 SocketFactoryPtr factory = make_shared<SocketFactory>(*this, incomingHandler, *si, *i);
289 factory->prepareAccept();
290 factories.push_back(factory);
291 }
292 } catch(const std::exception& e) {
293 LOG(SocketManager::className, "Error while loading server on port " + si->port +": " + e.what());
294 }331 }
295 }332 }
296333
334 core.getClientManager().prepareSupports(hasV4Address && hasV6Address);
335
297 io.run();336 io.run();
298337
299 io.reset();338 io.reset();
300339
=== modified file 'adchpp/SocketManager.h'
--- adchpp/SocketManager.h 2014-04-11 18:47:46 +0000
+++ adchpp/SocketManager.h 2014-05-01 19:31:53 +0000
@@ -94,6 +94,7 @@
94 friend class ManagedSocket;94 friend class ManagedSocket;
95 friend class SocketFactory;95 friend class SocketFactory;
9696
97 void prepareProtocol(ServerInfoPtr& si, bool v6);
97 void closeFactories();98 void closeFactories();
9899
99 Core &core;100 Core &core;
@@ -126,6 +127,9 @@
126 void onLoad(const SimpleXML& xml) throw();127 void onLoad(const SimpleXML& xml) throw();
127128
128 SocketManager(Core &core);129 SocketManager(Core &core);
130
131 bool hasV4Address;
132 bool hasV6Address;
129};133};
130134
131}135}
132136
=== modified file 'adchpp/Util.cpp'
--- adchpp/Util.cpp 2014-04-11 18:47:46 +0000
+++ adchpp/Util.cpp 2014-05-01 19:31:53 +0000
@@ -338,7 +338,11 @@
338}338}
339#endif339#endif
340340
341bool Util::isPrivateIp(std::string const& ip) {341bool Util::isPrivateIp(std::string const& ip, bool v6) {
342 if (v6) {
343 return strncmp(ip.c_str(), "fe80", 4) == 0;
344 }
345
342 struct in_addr addr;346 struct in_addr addr;
343347
344 addr.s_addr = inet_addr(ip.c_str());348 addr.s_addr = inet_addr(ip.c_str());
345349
=== modified file 'adchpp/Util.h'
--- adchpp/Util.h 2014-04-11 18:47:46 +0000
+++ adchpp/Util.h 2014-05-01 19:31:53 +0000
@@ -102,6 +102,7 @@
102 REASON_INVALID_DESCRIPTION,102 REASON_INVALID_DESCRIPTION,
103 REASON_WRITE_TIMEOUT,103 REASON_WRITE_TIMEOUT,
104 REASON_SOCKET_ERROR,104 REASON_SOCKET_ERROR,
105 REASON_HBRI,
105 REASON_LAST,106 REASON_LAST,
106 };107 };
107108
@@ -228,7 +229,7 @@
228 static uint32_t rand(uint32_t low, uint32_t high) { return rand(high-low) + low; }229 static uint32_t rand(uint32_t low, uint32_t high) { return rand(high-low) + low; }
229 static double randd() { return ((double)rand()) / ((double)0xffffffff); }230 static double randd() { return ((double)rand()) / ((double)0xffffffff); }
230231
231 ADCHPP_DLL static bool isPrivateIp(std::string const& ip);232 ADCHPP_DLL static bool isPrivateIp(std::string const& ip, bool v6);
232 ADCHPP_DLL static bool validateCharset(std::string const& field, int p);233 ADCHPP_DLL static bool validateCharset(std::string const& field, int p);
233};234};
234235
235236
=== modified file 'adchppd/adchppd.cpp'
--- adchppd/adchppd.cpp 2014-04-11 18:47:46 +0000
+++ adchppd/adchppd.cpp 2014-05-01 19:31:53 +0000
@@ -72,6 +72,8 @@
72 core.getSocketManager().setDisconnectTimeout(Util::toInt(xml.getChildData()));72 core.getSocketManager().setDisconnectTimeout(Util::toInt(xml.getChildData()));
73 } else if(xml.getChildName() == "LogTimeout") {73 } else if(xml.getChildName() == "LogTimeout") {
74 core.getClientManager().setLogTimeout(Util::toInt(xml.getChildData()));74 core.getClientManager().setLogTimeout(Util::toInt(xml.getChildData()));
75 } else if (xml.getChildName() == "HbriTimeout") {
76 core.getClientManager().setHbriTimeout(Util::toInt(xml.getChildData()));
75 }77 }
76 }78 }
7779
@@ -85,6 +87,11 @@
85 ServerInfoPtr server = make_shared<ServerInfo>();87 ServerInfoPtr server = make_shared<ServerInfo>();
86 server->port = xml.getChildAttrib("Port", Util::emptyString);88 server->port = xml.getChildAttrib("Port", Util::emptyString);
8789
90 server->bind4 = xml.getChildAttrib("BindAddress4", Util::emptyString);
91 server->bind6 = xml.getChildAttrib("BindAddress6", Util::emptyString);
92 server->address4 = xml.getChildAttrib("HubAddress4", Util::emptyString);
93 server->address6 = xml.getChildAttrib("HubAddress6", Util::emptyString);
94
88 if(xml.getBoolChildAttrib("TLS")) {95 if(xml.getBoolChildAttrib("TLS")) {
89 server->TLSParams.cert = File::makeAbsolutePath(xml.getChildAttrib("Certificate"));96 server->TLSParams.cert = File::makeAbsolutePath(xml.getChildAttrib("Certificate"));
90 server->TLSParams.pkey = File::makeAbsolutePath(xml.getChildAttrib("PrivateKey"));97 server->TLSParams.pkey = File::makeAbsolutePath(xml.getChildAttrib("PrivateKey"));
9198
=== modified file 'changelog.txt'
--- changelog.txt 2014-04-14 17:40:14 +0000
+++ changelog.txt 2014-05-01 19:31:53 +0000
@@ -2,6 +2,13 @@
2* [L#1206293] Fix crashes after calling +reload2* [L#1206293] Fix crashes after calling +reload
3* [L#1206293] Fix commands that output entity info3* [L#1206293] Fix commands that output entity info
44
5* Add support for hybrid IPv4/IPv6 client connectivity (maksis)
6* [L#1088638] Allow clients to reconnect in event of overflow (maksis)
7* [L#1106226] Fix a crash when joining the hub with a local IPv6 address (maksis)
8* Make login timeout work independently from other connecting users (maksis)
9* Allow configuring custom bind addresses (maksis)
10* Improve Lua scripts
11
5-- 2.11.1 2014-04-10 --12-- 2.11.1 2014-04-10 --
6* Improve Lua scripts13* Improve Lua scripts
714
815
=== modified file 'etc/adchpp.xml'
--- etc/adchpp.xml 2013-07-19 19:47:27 +0000
+++ etc/adchpp.xml 2014-05-01 19:31:53 +0000
@@ -51,6 +51,10 @@
5151
52 <!-- Timeout (ms) before disconnecting users whose login process is taking too long. -->52 <!-- Timeout (ms) before disconnecting users whose login process is taking too long. -->
53 <LogTimeout>10000</LogTimeout>53 <LogTimeout>10000</LogTimeout>
54
55 <!-- Timeout (ms) before aborting validation for the secondary IP protocol.
56 The login procedure will continue normally with the primary IP protocol then. -->
57 <HbriTimeout>3000</HbriTimeout>
54 </Settings>58 </Settings>
5559
56 <Servers>60 <Servers>
@@ -59,15 +63,22 @@
5963
60 To create secure connections, set TLS="1" and define the following (preferably absolute)64 To create secure connections, set TLS="1" and define the following (preferably absolute)
61 paths: Certificate, PrivateKey, TrustedPath, DHParams. An example secure server setting:65 paths: Certificate, PrivateKey, TrustedPath, DHParams. An example secure server setting:
62 <Server Port="2780" TLS="1" Certificate="certs/cacert.pem" PrivateKey="certs/privkey.pem" TrustedPath="certs/trusted/" DHParams="certs/dhparam.pem"/>66 <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="::"/>
6367
64 Simple OpenSSL commands to generate files used for secure connections:68 Simple OpenSSL commands to generate files used for secure connections:
65 openssl genrsa -out privkey.pem 204869 openssl genrsa -out privkey.pem 2048
66 openssl req -new -x509 -key privkey.pem -out cacert.pem -days 109570 openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095
67 openssl dhparam -outform PEM -out dhparam.pem 102471 openssl dhparam -outform PEM -out dhparam.pem 1024
6872
69 Alternatively, you can use the cert generator contributed on73 Alternatively, you can use the cert generator contributed on
70 <http://launchpadlibrarian.net/31960965/Cert_Generator.7z>.74 <http://launchpadlibrarian.net/31960965/Cert_Generator.7z>.
75
76 To allow hybrid connectivity, add address fields for the used protocols: HubAddress4 and HubAddress6. You may also use the same
77 DNS entry for both if it has A and AAAA records. You may also use plain IP addresses.
78 Example:
79 <Server Port="2780" HubAddress4="mydomain4.net" HubAddress6="mydomain6.net"/>
80
81 Bind addresses may be set with: BindAddress4 and BindAddress6 (connections will be accepted for both protocols if none is set)
7182
72 -->83 -->
73 <Server Port="2780"/>84 <Server Port="2780"/>
7485
=== modified file 'swig/adchpp.i'
--- swig/adchpp.i 2013-07-19 19:47:27 +0000
+++ swig/adchpp.i 2014-05-01 19:31:53 +0000
@@ -126,7 +126,10 @@
126typedef shared_ptr<ManagedConnection> ManagedConnectionPtr;126typedef shared_ptr<ManagedConnection> ManagedConnectionPtr;
127127
128struct ServerInfo {128struct ServerInfo {
129 std::string ip;129 std::string bind4;
130 std::string bind6;
131 std::string address4;
132 std::string address6;
130 std::string port;133 std::string port;
131134
132 TLSInfo TLSParams;135 TLSInfo TLSParams;
@@ -291,7 +294,7 @@
291 static uint32_t rand(uint32_t low, uint32_t high);294 static uint32_t rand(uint32_t low, uint32_t high);
292 static double randd();295 static double randd();
293 296
294 static bool isPrivateIp(std::string const& ip);297 static bool isPrivateIp(std::string const& ip, bool v6);
295 static bool validateCharset(std::string const& field, int p);298 static bool validateCharset(std::string const& field, int p);
296299
297};300};
@@ -723,7 +726,7 @@
723 bool verifyPassword(Entity& c, const std::string& password, const ByteVector& salt, const std::string& suppliedHash);726 bool verifyPassword(Entity& c, const std::string& password, const ByteVector& salt, const std::string& suppliedHash);
724 bool verifyHashedPassword(Entity& c, const ByteVector& hashedPassword, int64_t hashedPasswordLen,727 bool verifyHashedPassword(Entity& c, const ByteVector& hashedPassword, int64_t hashedPasswordLen,
725 const ByteVector& salt, const std::string& suppliedHash) throw();728 const ByteVector& salt, const std::string& suppliedHash) throw();
726 bool verifyIp(Client& c, AdcCommand& cmd) throw();729 bool verifyIp(Client& c, AdcCommand& cmd, bool isHbriConn) throw();
727 bool verifyCID(Entity& c, AdcCommand& cmd) throw();730 bool verifyCID(Entity& c, AdcCommand& cmd) throw();
728 bool verifyOverflow(Entity& c);731 bool verifyOverflow(Entity& c);
729 void setState(Entity& c, Entity::State newState) throw();732 void setState(Entity& c, Entity::State newState) throw();
730733
=== modified file 'swig/lua.i'
--- swig/lua.i 2014-04-13 15:01:43 +0000
+++ swig/lua.i 2014-05-01 19:31:53 +0000
@@ -322,7 +322,7 @@
322 if(ret) {322 if(ret) {
323 return *reinterpret_cast<SWIGLUA_REF*>(ret);323 return *reinterpret_cast<SWIGLUA_REF*>(ret);
324 }324 }
325 return {0, 0};325 return SWIGLUA_REF();
326 }326 }
327327
328 void setPluginData(const PluginDataHandle& handle, SWIGLUA_REF data) {328 void setPluginData(const PluginDataHandle& handle, SWIGLUA_REF data) {

Subscribers

People subscribed via source and target branches