Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / net / login_client.cpp
blob0f4383e16e61442b978abdf263d0faefe0df510c
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stdnet.h"
19 #include "nel/misc/system_info.h"
21 #include "nel/net/callback_client.h"
23 #include "nel/net/login_cookie.h"
24 #include "nel/net/login_client.h"
26 #include "nel/net/udp_sock.h"
28 using namespace std;
29 using namespace NLMISC;
31 namespace NLNET {
34 CLoginClient::TShardList CLoginClient::ShardList;
35 CCallbackClient *CLoginClient::_LSCallbackClient;
39 // CALLBACK FROM THE FS (Front-end Service)
42 // Callback for answer of the request shard
43 static bool ShardValidate;
44 static string ShardValidateReason;
45 static void cbShardValidate (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
48 // S14: receive "SV" message from FES
51 msgin.serial (ShardValidateReason);
52 ShardValidate = true;
55 static TCallbackItem FESCallbackArray[] =
57 { "SV", cbShardValidate },
61 // CALLBACK FROM THE LS (Login Service)
64 // Callback for answer of the login password.
65 static bool VerifyLoginPassword;
66 static string VerifyLoginPasswordReason;
67 static void cbVerifyLoginPassword (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
70 // S04: receive the "VLP" message from LS
73 msgin.serial (VerifyLoginPasswordReason);
74 if(VerifyLoginPasswordReason.empty())
76 uint32 nbshard;
77 msgin.serial (nbshard);
79 CLoginClient::ShardList.clear ();
80 VerifyLoginPasswordReason.clear();
82 // get the shard list
83 for (uint i = 0; i < nbshard; i++)
85 CLoginClient::CShardEntry se;
86 msgin.serial (se.Name, se.NbPlayers, se.Id);
87 CLoginClient::ShardList.push_back (se);
90 VerifyLoginPassword = true;
93 // Callback for answer of the request shard
94 static bool ShardChooseShard;
95 static string ShardChooseShardReason;
96 static string ShardChooseShardAddr;
97 static string ShardChooseShardCookie;
98 static void cbShardChooseShard (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
101 // S11: receive "SCS" message from LS
104 msgin.serial (ShardChooseShardReason);
106 if (ShardChooseShardReason.empty())
108 msgin.serial (ShardChooseShardCookie);
109 msgin.serial (ShardChooseShardAddr);
111 ShardChooseShard = true;
114 static TCallbackItem LSCallbackArray[] =
116 { "VLP", cbVerifyLoginPassword },
117 { "SCS", cbShardChooseShard },
120 string CLoginClient::authenticate(const string &loginServiceAddr, const ucstring &login, const string &cpassword, const string &application)
122 string result = authenticateBegin(loginServiceAddr, login, cpassword, application);
123 if (!result.empty()) return result;
124 while (CLoginClient::authenticateUpdate(result)) nlSleep(10);
125 return result;
128 string CLoginClient::authenticateBegin(const string &loginServiceAddr, const ucstring &login, const string &cpassword, const string &application)
130 VerifyLoginPasswordReason.clear();
131 VerifyLoginPassword = false;
133 // S01: connect to the LS
136 if(_LSCallbackClient == 0)
138 _LSCallbackClient = new CCallbackClient();
139 _LSCallbackClient->addCallbackArray(LSCallbackArray, sizeof(LSCallbackArray) / sizeof(LSCallbackArray[0]));
142 string addr = loginServiceAddr;
143 if(addr.find(":") == string::npos)
144 addr += ":49997";
145 if(_LSCallbackClient->connected())
146 _LSCallbackClient->disconnect();
147 _LSCallbackClient->connect (CInetAddress(addr));
149 catch (const ESocket &e)
151 delete _LSCallbackClient;
152 _LSCallbackClient = 0;
153 nlwarning("Connection refused to LS (addr:%s): %s", loginServiceAddr.c_str(), e.what());
154 return toString("Connection refused to LS (addr:%s): %s", loginServiceAddr.c_str(), e.what());
157 // S02: create and send the "VLP" message
158 CMessage msgout("VLP");
159 msgout.serial(const_cast<ucstring&>(login));
160 msgout.serial(const_cast<string&>(cpassword));
161 msgout.serial(const_cast<string&>(application));
162 _LSCallbackClient->send(msgout);
164 return "";
167 // returns true if it needs to be called again
168 // error not empty if something went wrong
169 bool CLoginClient::authenticateUpdate(string &error)
171 if (!_LSCallbackClient)
173 error = "CLoginClient::authenticateBegin() must be called first";
174 nlwarning("CLoginClient::authenticateUpdate(): %s", error.c_str());
175 return false;
177 if (!_LSCallbackClient->connected())
179 error = "Disconnected from LS";
180 nlwarning("CLoginClient::authenticateUpdate(): %s", error.c_str());
181 delete _LSCallbackClient;
182 _LSCallbackClient = 0;
183 return false;
185 _LSCallbackClient->update();
186 if (VerifyLoginPassword)
188 error = VerifyLoginPasswordReason;
189 if (!error.empty())
191 nlwarning("CLoginClient::authenticateUpdate(): %s", error.c_str());
192 _LSCallbackClient->disconnect ();
193 delete _LSCallbackClient;
194 _LSCallbackClient = 0;
196 return false;
198 return true; // no news, try again
201 string CLoginClient::connectToShard(CLoginCookie &lc, const std::string &addr, CCallbackClient &cnx)
203 nlassert (!cnx.connected());
208 // S12: connect to the FES and send "SV" message to the FES
210 cnx.connect (CInetAddress(addr));
211 cnx.addCallbackArray (FESCallbackArray, sizeof(FESCallbackArray)/sizeof(FESCallbackArray[0]));
213 // send the cookie
214 CMessage msgout2 ("SV");
215 msgout2.serial (lc);
216 cnx.send (msgout2);
218 // wait the answer of the connection
219 ShardValidate = false;
220 while (cnx.connected() && !ShardValidate)
222 cnx.update ();
223 nlSleep(10);
226 // have we received the answer?
227 if (!ShardValidate) return "FES disconnect me";
229 catch (const ESocket &e)
231 return string("FES refused the connection (") + e.what () + ")";
234 return ShardValidateReason;
237 string CLoginClient::connectToShard (const std::string &addr, CUdpSock &cnx)
239 nlassert (!cnx.connected());
244 // S12: connect to the FES. Note: In UDP mode, it's the user that have to send the cookie to the front end
246 // If a personal firewall such as ZoneAlarm is installed and permission not granted yet,
247 // the connect blocks until the user makes a choice.
248 // If the user denies the connection, the exception ESocket is thrown.
249 // Other firewalls such as Kerio make the send() fail instead.
251 cnx.connect (CInetAddress(addr));
253 catch (const ESocket &e)
255 return string("FES refused the connection (") + e.what () + ")";
258 return ShardValidateReason;
261 string CLoginClient::connectToShard (const std::string &addr, CUdpSimSock &cnx)
263 nlassert (!cnx.connected());
269 // S12: connect to the FES. Note: In UDP mode, it's the user that have to send the cookie to the front end
271 // See firewall comment in connectToShard(string,CUdpSock)
273 cnx.connect (CInetAddress(addr));
275 catch (const ESocket &e)
277 return string("FES refused the connection (") + e.what () + ")";
280 return ShardValidateReason;
283 string CLoginClient::confirmConnection(sint32 shardId)
285 nlassert(_LSCallbackClient != 0 && _LSCallbackClient->connected());
288 // S05: create and send the "CS" message with the shardid choice to the LS
291 if (ShardList.empty())
293 _LSCallbackClient->disconnect();
294 return "No shard available";
297 CLoginClient::CShardEntry *s = getShard(shardId);
298 if (!s)
300 _LSCallbackClient->disconnect();
301 return "Invalid shard selected";
304 // send CS
305 CMessage msgout ("CS");
306 msgout.serial (s->Id);
307 _LSCallbackClient->send (msgout);
309 // wait the answer
310 ShardChooseShard = false;
311 while (_LSCallbackClient->connected() && !ShardChooseShard)
313 _LSCallbackClient->update ();
314 nlSleep(10);
317 // have we received the answer?
318 if (!ShardChooseShard)
320 delete _LSCallbackClient;
321 _LSCallbackClient = 0;
322 return "CLoginClientMtp::confirmConnection(): LS disconnects me";
324 else
326 _LSCallbackClient->disconnect ();
327 delete _LSCallbackClient;
328 _LSCallbackClient = 0;
331 if (!ShardChooseShardReason.empty())
333 return ShardChooseShardReason;
336 // ok, we can try to connect to the good front end
338 nlinfo("addr: '%s' cookie: %s", ShardChooseShardAddr.c_str(), ShardChooseShardCookie.c_str());
340 return "";
343 string CLoginClient::wantToConnectToShard(sint32 shardId, string &ip, string &cookie)
345 string res = confirmConnection(shardId);
346 if (!res.empty()) return res;
348 ip = ShardChooseShardAddr;
349 cookie = ShardChooseShardCookie;
351 return "";
354 string CLoginClient::selectShardBegin(sint32 shardId)
356 nlassert(_LSCallbackClient != 0 && _LSCallbackClient->connected());
358 ShardChooseShardReason.clear();
359 ShardChooseShard = false;
361 if (ShardList.empty())
363 _LSCallbackClient->disconnect();
364 delete _LSCallbackClient;
365 _LSCallbackClient = 0;
366 return "No shard available";
368 CLoginClient::CShardEntry *s = getShard(shardId);
369 if (!s)
371 _LSCallbackClient->disconnect();
372 delete _LSCallbackClient;
373 _LSCallbackClient = 0;
374 return "Invalid shard selected";
377 // S05: create and send the "CS" message with the shardid choice to the LS
378 CMessage msgout ("CS");
379 msgout.serial (s->Id);
380 _LSCallbackClient->send (msgout);
382 return "";
385 bool CLoginClient::selectShardUpdate(string &error, string &ip, string &cookie)
387 if (!_LSCallbackClient)
389 error = "CLoginClient::selectShardBegin() must be called first";
390 nlwarning("CLoginClient::selectShardUpdate(): %s", error.c_str());
391 return false;
393 if (!_LSCallbackClient->connected())
395 error = "Disconnected from LS";
396 nlwarning("CLoginClient::selectShardUpdate(): %s", error.c_str());
397 delete _LSCallbackClient;
398 _LSCallbackClient = 0;
399 return false;
401 _LSCallbackClient->update();
402 if (ShardChooseShard)
404 error = ShardChooseShardReason;
405 ip = ShardChooseShardAddr;
406 cookie = ShardChooseShardCookie;
407 if (!error.empty()) nlwarning("CLoginClient::selectShardUpdate(): %s", error.c_str());
408 else nlinfo("addr: '%s' cookie: %s", ShardChooseShardAddr.c_str(), ShardChooseShardCookie.c_str());
409 _LSCallbackClient->disconnect ();
410 delete _LSCallbackClient;
411 _LSCallbackClient = 0;
412 return false;
414 return true;
417 CLoginClient::CShardEntry *CLoginClient::getShard (sint32 shardId)
419 for(TShardList::iterator it=ShardList.begin();it!=ShardList.end();it++)
421 if((*it).Id == shardId)
422 return &(*it);
424 return 0;
428 } // NLNET