1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
19 /**************************************************************************
20 ********************* THIS CLASS IS DEPRECATED ****************************
21 **************************************************************************/
23 # pragma message(NL_LOC_WRN "You are using a deprecated feature of NeL, consider rewriting your code with replacement feature")
25 # warning "You are using a deprecated feature of NeL, consider rewriting your code with replacement feature"
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"
37 using namespace NLMISC
;
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
)
77 for (i
= 0; i
< Base
.NetBase
.size (); i
++)
79 if (!Base
.NetBase
[i
]->connected ())
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
);
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
);
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
];
178 void CNetManager::addServer (const std::string
&serviceName
, uint16 servicePort
, bool external
)
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
);
222 CNamingClient::registerService (serviceName
, addr
, sid
);
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
);
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 ();
332 if (_NextUpdateTime
== 0)
334 _NextUpdateTime
= t0
+ timeout
;
338 TTime err
= t0
- _NextUpdateTime
;
339 _NextUpdateTime
+= timeout
;
341 // if we are too late, resync to the next value
342 while (err
> timeout
)
345 _NextUpdateTime
+= timeout
;
349 if (timeout
< 0) timeout
= 0;
353 // sint64 p2 = CTime::getPerformanceTime ();
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 ();
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
)
402 // Enable windows multithreading before rescanning all connections
403 // slow down the layer H_BEFORE (CNetManager_update_nlSleep);
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
)));
461 uint64
CNetManager::getBytesSent ()
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 ();
474 uint64
CNetManager::getBytesReceived ()
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 ();
487 uint64
CNetManager::getSendQueueSize ()
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 ();
500 uint64
CNetManager::getReceiveQueueSize ()
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 ();