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