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

Proposed by maksis on 2013-11-12
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 2013-11-12 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.
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.

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*

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 on 2013-11-29
661. By maksis on 2013-11-29

Remove string::pop_back() for better compatibility

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

lp:~maksis/adchpp/adchpp-hbri updated on 2014-05-01
662. By maksis on 2014-03-29

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

663. By maksis on 2014-04-13

Merge

664. By maksis on 2014-04-13

Merge

665. By maksis on 2014-05-01

Sync

Unmerged revisions

665. By maksis on 2014-05-01

Sync

664. By maksis on 2014-04-13

Merge

663. By maksis on 2014-04-13

Merge

662. By maksis on 2014-03-29

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

661. By maksis on 2013-11-29

Remove string::pop_back() for better compatibility

660. By maksis on 2013-11-12

Readd 629 and 630

659. By maksis on 2013-11-12

Revert some changes, update changelog

658. By maksis on 2013-11-11

- 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 on 2013-11-10

HBRI works also for registered users

656. By maksis on 2013-11-10

Resolve the configured hub addresses, bug fixes

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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) {

Subscribers

People subscribed via source and target branches