Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / net / net_manager.cpp
blob2c23cbdfd8a43fdcdd74148e3336ac3401713187
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 /**************************************************************************
20 ********************* THIS CLASS IS DEPRECATED ****************************
21 **************************************************************************/
22 #ifdef NL_OS_WINDOWS
23 # pragma message(NL_LOC_WRN "You are using a deprecated feature of NeL, consider rewriting your code with replacement feature")
24 #else // NL_OS_UNIX
25 # warning "You are using a deprecated feature of NeL, consider rewriting your code with replacement feature"
26 #endif
28 #include "nel/misc/time_nl.h"
30 #include "nel/net/naming_client.h"
31 #include "nel/net/callback_client.h"
32 #include "nel/net/callback_server.h"
33 #include "nel/net/naming_client.h"
34 #include "nel/net/net_manager.h"
36 using namespace std;
37 using namespace NLMISC;
39 namespace NLNET {
42 CNetManager::TBaseMap CNetManager::_BaseMap;
44 CCallbackNetBase::TRecordingState CNetManager::_RecordingState;
46 TTime CNetManager::_NextUpdateTime = 0;
48 static void nmNewConnection (TSockId from, void *arg)
50 nlassert (arg != NULL);
51 CBaseStruct *basest = (CBaseStruct *)arg;
53 nldebug("HNETL4: nmNewConnection() from service '%s'", basest->Name.c_str ());
55 // call the client callback if necessary
56 if (basest->ConnectionCallback != NULL)
57 basest->ConnectionCallback (basest->Name, from, basest->ConnectionCbArg);
60 static void nmNewDisconnection (TSockId from, void *arg)
62 nlassert (arg != NULL);
63 CBaseStruct *basest = (CBaseStruct *)arg;
65 nldebug("HNETL4: nmNewDisconnection() from service '%s'", basest->Name.c_str ());
67 // call the client callback if necessary
68 if (basest->DisconnectionCallback != NULL)
69 basest->DisconnectionCallback (basest->Name, from, basest->DisconnectionCbArg);
73 // find a not connected callbackclient or create a new one and connect to the Addr
74 void CNetManager::createConnection(CBaseStruct &Base, const CInetAddress &Addr, const string& name)
76 uint i;
77 for (i = 0; i < Base.NetBase.size (); i++)
79 if (!Base.NetBase[i]->connected ())
81 break;
84 if (i == Base.NetBase.size ())
86 CCallbackClient *cc = new CCallbackClient( _RecordingState, name+string(".nmr") );
87 Base.NetBase.push_back (cc);
90 CCallbackClient *cc = dynamic_cast<CCallbackClient *>(Base.NetBase[i]);
92 cc->CCallbackNetBase::setDisconnectionCallback (nmNewDisconnection, (void*) &Base);
94 try
96 cc->connect (Addr);
98 if (Base.ConnectionCallback != NULL)
99 Base.ConnectionCallback (Base.Name, cc->getSockId(), Base.ConnectionCbArg);
101 catch (ESocketConnectionFailed &e)
103 nlinfo ("HNETL4: can't connect now (%s)", e.what ());
108 void RegistrationBroadcast (const std::string &name, TServiceId sid, const vector<CInetAddress> &addr)
110 nldebug("HNETL4: RegistrationBroadcast() of service %s-%hu", name.c_str (), (uint16)sid.get());
112 // find if this new service is interesting
113 for (CNetManager::ItBaseMap itbm = CNetManager::_BaseMap.begin (); itbm != CNetManager::_BaseMap.end (); itbm++)
115 if ((*itbm).second.Type == CBaseStruct::Client && !(*itbm).second.NetBase[0]->connected())
117 if (name == (*itbm).first)
119 // ok! it's cool, the service is here, go and connect to him!
120 // ace warning don't work if more than one connection
121 CNetManager::createConnection ((*itbm).second, addr[0], name);
124 else if ((*itbm).second.Type == CBaseStruct::Group)
126 // ok, it's a group, try to see if it wants this!
127 for (uint i = 0; i < (*itbm).second.ServiceNames.size (); i++)
129 if ((*itbm).second.ServiceNames[i] == name)
131 // ace warning don't work if more than one connection
132 CNetManager::createConnection ((*itbm).second, addr[0], name);
133 break;
141 static void UnregistrationBroadcast (const std::string &name, TServiceId sid, const vector<CInetAddress> &addr)
143 nldebug("HNETL4: UnregistrationBroadcast() of service %s-%hu", name.c_str (), (uint16)sid.get());
146 void CNetManager::init (const CInetAddress *addr, CCallbackNetBase::TRecordingState rec )
148 if (addr == NULL) return;
150 _RecordingState = rec;
152 // connect to the naming service (may generate a ESocketConnectionFailed exception)
154 vector<CInetAddress> laddr = CInetAddress::localAddresses();
155 CNamingClient::connect( *addr, _RecordingState, laddr );
157 // connect the callback to know when a new service comes in or goes down
158 CNamingClient::setRegistrationBroadcastCallback (RegistrationBroadcast);
159 CNamingClient::setUnregistrationBroadcastCallback (UnregistrationBroadcast);
162 void CNetManager::release ()
164 if (CNamingClient::connected ())
165 CNamingClient::disconnect ();
167 for (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)
169 for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
171 (*itbm).second.NetBase[i]->disconnect ();
172 delete (*itbm).second.NetBase[i];
175 _BaseMap.clear ();
178 void CNetManager::addServer (const std::string &serviceName, uint16 servicePort, bool external)
180 TServiceId sid;
181 addServer (serviceName, servicePort, sid, external);
184 void CNetManager::addServer (const std::string &serviceName, uint16 servicePort, TServiceId &sid, bool external)
186 nldebug ("HNETL4: Adding server '%s' in CNetManager", serviceName.c_str ());
187 ItBaseMap itbm = find (serviceName);
189 // check if it's a new server
190 nlassert ((*itbm).second.NetBase.empty());
192 CCallbackServer *cs = new CCallbackServer( _RecordingState, serviceName+string(".nmr") );
193 (*itbm).second.NetBase.push_back (cs);
195 (*itbm).second.Type = CBaseStruct::Server;
197 // install the server
199 cs->setConnectionCallback (nmNewConnection, (void*) &((*itbm).second));
200 cs->CCallbackNetBase::setDisconnectionCallback (nmNewDisconnection, (void*) &((*itbm).second));
202 if (servicePort == 0)
204 nlassert (CNamingClient::connected ());
205 servicePort = CNamingClient::queryServicePort ();
208 cs->init (servicePort);
210 // register the server to the naming service if we are connected to Naming Service
212 if (CNamingClient::connected () && !external)
214 //CInetAddress addr = CInetAddress::localHost ();
215 //addr.setPort (servicePort);
216 vector<CInetAddress> addr = CInetAddress::localAddresses();
217 for (uint i = 0; i < addr.size(); i++)
218 addr[i].setPort(servicePort);
220 if (sid.get() == 0)
222 CNamingClient::registerService (serviceName, addr, sid);
224 else
226 CNamingClient::registerServiceWithSId (serviceName, addr, sid);
229 nlinfo ("HNETL4: Server '%s' added, registered and listen to port %hu", serviceName.c_str (), servicePort);
233 void CNetManager::addClient (const std::string &serviceName, const std::string &addr, bool autoRetry)
235 nldebug ("HNETL4: Adding client '%s' with addr '%s' in CNetManager", serviceName.c_str (), addr.c_str());
236 ItBaseMap itbm = find (serviceName);
238 // it's a new client, add the connection
239 (*itbm).second.Type = CBaseStruct::ClientWithAddr;
240 (*itbm).second.AutoRetry = autoRetry;
242 if ((*itbm).second.ServiceNames.empty())
244 (*itbm).second.ServiceNames.push_back(addr);
246 else
248 (*itbm).second.ServiceNames[0] = addr;
251 nlassert ((*itbm).second.NetBase.size() < 2);
253 createConnection ((*itbm).second, addr, serviceName);
257 void CNetManager::addClient (const std::string &serviceName)
259 nlassert (CNamingClient::connected ());
260 nldebug ("HNETL4: Adding client '%s' in CNetManager", serviceName.c_str ());
261 ItBaseMap itbm = find (serviceName);
263 // check if it's a new client
264 nlassert ((*itbm).second.NetBase.empty());
266 CCallbackClient *cc = new CCallbackClient( _RecordingState, serviceName+string(".nmr") ); // ? - would not work if several clients with the same name
267 (*itbm).second.NetBase.push_back (cc);
269 (*itbm).second.Type = CBaseStruct::Client;
271 cc->CCallbackNetBase::setDisconnectionCallback (nmNewDisconnection, (void*) &((*itbm).second));
273 // find the service in the naming_service and connect if exists
274 if (CNamingClient::lookupAndConnect (serviceName, *cc))
276 // call the user that we are connected
277 if ((*itbm).second.ConnectionCallback != NULL)
278 (*itbm).second.ConnectionCallback (serviceName, cc->getSockId(), (*itbm).second.ConnectionCbArg);
284 void CNetManager::addGroup (const std::string &groupName, const std::string &serviceName)
286 nlassert (CNamingClient::connected ());
287 nldebug ("HNETL4: Adding '%s' to group '%s' in CNetManager", serviceName.c_str (), groupName.c_str());
288 ItBaseMap itbm = find (groupName);
290 (*itbm).second.Type = CBaseStruct::Group;
292 // check if you don't already add this service in this group
293 vector<string>::iterator it = std::find ((*itbm).second.ServiceNames.begin(), (*itbm).second.ServiceNames.end(), serviceName);
294 nlassert (it == (*itbm).second.ServiceNames.end());
296 (*itbm).second.ServiceNames.push_back(serviceName);
299 // find the service in the naming_service and connect if exists
300 vector<CInetAddress> addrs;
301 CNamingClient::lookupAll (serviceName, addrs);
303 // connect to all these services
304 for (uint i = 0; i < addrs.size (); i++)
306 createConnection ((*itbm).second, addrs[i], serviceName);
311 void CNetManager::addCallbackArray (const std::string &serviceName, const TCallbackItem *callbackarray, CStringIdArray::TStringId arraysize)
313 nldebug ("HNETL4: addingCallabckArray() for service '%s'", serviceName.c_str ());
314 ItBaseMap itbm = find (serviceName);
315 for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
317 // if ((*itbm).second.NetBase[i]->connected())
318 (*itbm).second.NetBase[i]->addCallbackArray (callbackarray, arraysize);
322 void CNetManager::update (TTime timeout)
324 // nldebug ("HNETL4: update()");
326 // sint64 p1 = CTime::getPerformanceTime ();
328 TTime t0 = CTime::getLocalTime ();
330 if (timeout > 0)
332 if (_NextUpdateTime == 0)
334 _NextUpdateTime = t0 + timeout;
336 else
338 TTime err = t0 - _NextUpdateTime;
339 _NextUpdateTime += timeout;
341 // if we are too late, resync to the next value
342 while (err > timeout)
344 err -= timeout;
345 _NextUpdateTime += timeout;
348 timeout -= err;
349 if (timeout < 0) timeout = 0;
353 // sint64 p2 = CTime::getPerformanceTime ();
355 while (true)
357 for (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)
359 for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
361 // we get and treat all messages in this connection
362 (*itbm).second.NetBase[i]->update (0);
363 if ((*itbm).second.NetBase[i]->connected())
365 // if connected, update
366 // (*itbm).second.NetBase[i]->update ();
368 else
370 static TTime lastTime = CTime::getLocalTime();
371 if (CTime::getLocalTime() - lastTime > 5000)
373 lastTime = CTime::getLocalTime();
375 // if not connected, try to connect ClientWithAddr
376 if ((*itbm).second.Type == CBaseStruct::ClientWithAddr && (*itbm).second.AutoRetry)
378 CCallbackClient *cc = dynamic_cast<CCallbackClient *>((*itbm).second.NetBase[i]);
381 nlassert ((*itbm).second.ServiceNames.size()==1);
382 cc->connect (CInetAddress((*itbm).second.ServiceNames[0]));
384 if ((*itbm).second.ConnectionCallback != NULL)
385 (*itbm).second.ConnectionCallback ((*itbm).second.Name, cc->getSockId(), (*itbm).second.ConnectionCbArg);
387 catch (ESocketConnectionFailed &e)
389 // can't connect now, try later
390 nlinfo("HNETL4: can't connect now to %s (reason: %s)", (*itbm).second.ServiceNames[0].c_str(), e.what());
398 // If it's the end, don't nlSleep()
399 if (CTime::getLocalTime() - t0 > timeout)
400 break;
402 // Enable windows multithreading before rescanning all connections
403 // slow down the layer H_BEFORE (CNetManager_update_nlSleep);
404 nlSleep (1);
405 // slow down the layer H_AFTER (CNetManager_update_nlSleep);
408 // sint64 p3 = CTime::getPerformanceTime ();
410 if (CNamingClient::connected ())
411 CNamingClient::update ();
413 // sint64 p4 = CTime::getPerformanceTime ();
415 // nlinfo("time : %f %f %f %d", CTime::ticksToSecond(p2-p1), CTime::ticksToSecond(p3-p2), CTime::ticksToSecond(p4-p3), timeout);
419 void CNetManager::send (const std::string &serviceName, const CMessage &buffer, TSockId hostid)
421 nldebug ("HNETL4: send for service '%s' message %s to %s", serviceName.c_str(), buffer.toString().c_str(), hostid->asString().c_str());
422 ItBaseMap itbm = find (serviceName);
423 for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
425 if ((*itbm).second.NetBase[i]->connected())
426 (*itbm).second.NetBase[i]->send (buffer, hostid);
430 CCallbackNetBase *CNetManager::getNetBase (const std::string &serviceName)
432 ItBaseMap itbm = find (serviceName);
433 return (*itbm).second.NetBase[0];
436 void CNetManager::setConnectionCallback (const std::string &serviceName, TNetManagerCallback cb, void *arg)
438 nldebug ("HNETL4: setConnectionCallback() for service '%s'", serviceName.c_str ());
439 ItBaseMap itbm = find (serviceName);
440 (*itbm).second.ConnectionCallback = cb;
441 (*itbm).second.ConnectionCbArg = arg;
444 void CNetManager::setDisconnectionCallback (const std::string &serviceName, TNetManagerCallback cb, void *arg)
446 nldebug ("HNETL4: setDisconnectionCallback() for service '%s'", serviceName.c_str ());
447 ItBaseMap itbm = find (serviceName);
448 (*itbm).second.DisconnectionCallback = cb;
449 (*itbm).second.DisconnectionCbArg = arg;
453 CNetManager::ItBaseMap CNetManager::find (const std::string &serviceName)
455 // find the service or add it if not found
456 pair<ItBaseMap, bool> p;
457 p = _BaseMap.insert (make_pair (serviceName, CBaseStruct (serviceName)));
458 return p.first;
461 uint64 CNetManager::getBytesSent ()
463 uint64 sent = 0;
464 for (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)
466 for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
468 sent += (*itbm).second.NetBase[i]->getBytesSent ();
471 return sent;
474 uint64 CNetManager::getBytesReceived ()
476 uint64 received = 0;
477 for (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)
479 for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
481 received += (*itbm).second.NetBase[i]->getBytesReceived ();
484 return received;
487 uint64 CNetManager::getSendQueueSize ()
489 uint64 val = 0;
490 for (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)
492 for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
494 val += (*itbm).second.NetBase[i]->getSendQueueSize ();
497 return val;
500 uint64 CNetManager::getReceiveQueueSize ()
502 uint64 val = 0;
503 for (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)
505 for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
507 val += (*itbm).second.NetBase[i]->getReceiveQueueSize ();
510 return val;
513 } // NLNET