# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

net_manager.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 
00027 
00028 
00029 /**************************************************************************
00030 ********************* THIS CLASS IS DEPRECATED ****************************
00031 **************************************************************************/
00032 
00033 
00034 
00035 
00036 #include "stdnet.h"
00037 
00038 #include "nel/misc/string_id_array.h"
00039 #include "nel/misc/time_nl.h"
00040 
00041 #include "nel/net/naming_client.h"
00042 
00043 #include "nel/net/callback_client.h"
00044 #include "nel/net/callback_server.h"
00045 
00046 #include "nel/net/naming_client.h"
00047 
00048 #include "nel/net/net_manager.h"
00049 
00050 using namespace std;
00051 using namespace NLMISC;
00052 
00053 namespace NLNET {
00054 
00055 
00056 CNetManager::TBaseMap   CNetManager::_BaseMap;
00057 
00058 CCallbackNetBase::TRecordingState       CNetManager::_RecordingState;
00059 
00060 TTime CNetManager::_NextUpdateTime = 0;
00061 
00062 static void nmNewConnection (TSockId from, void *arg)
00063 {
00064         nlassert (arg != NULL);
00065         CBaseStruct *basest = (CBaseStruct *)arg;
00066 
00067         nldebug("HNETL4: nmNewConnection() from service '%s'", basest->Name.c_str ());
00068 
00069         // call the client callback if necessary
00070         if (basest->ConnectionCallback != NULL)
00071                 basest->ConnectionCallback (basest->Name, from, basest->ConnectionCbArg);
00072 }
00073 
00074 static void nmNewDisconnection (TSockId from, void *arg)
00075 {
00076         nlassert (arg != NULL);
00077         CBaseStruct *basest = (CBaseStruct *)arg;
00078 
00079         nldebug("HNETL4: nmNewDisconnection() from service '%s'", basest->Name.c_str ());
00080 
00081         // call the client callback if necessary
00082         if (basest->DisconnectionCallback != NULL)
00083                 basest->DisconnectionCallback (basest->Name, from, basest->DisconnectionCbArg);
00084 
00086 
00087         // on a client, we have to clear the associations
00088         if (basest->Type != CBaseStruct::Server)
00089         {
00090                 nlassert (basest->NetBase.size() == 1);
00091                 basest->NetBase[0]->getSIDA ().clear ();
00092         }
00093 }
00094 
00095 
00096 // find a not connected callbackclient or create a new one and connect to the Addr
00097 void CNetManager::createConnection(CBaseStruct &Base, const CInetAddress &Addr, const string& name)
00098 {
00099         uint i;
00100         for (i = 0; i < Base.NetBase.size (); i++)
00101         {
00102                 if (!Base.NetBase[i]->connected ())
00103                 {
00104                         break;
00105                 }
00106         }
00107         if (i == Base.NetBase.size ())
00108         {
00109                 CCallbackClient *cc = new CCallbackClient( _RecordingState, name+string(".nmr") );
00110                 Base.NetBase.push_back (cc);
00111         }
00112         
00113         CCallbackClient *cc = dynamic_cast<CCallbackClient *>(Base.NetBase[i]);
00114 
00115         cc->CCallbackNetBase::setDisconnectionCallback (nmNewDisconnection, (void*) &Base);
00116 
00117         try
00118         {
00119                 cc->connect (Addr);
00120 
00121                 if (Base.ConnectionCallback != NULL)
00122                         Base.ConnectionCallback (Base.Name, cc->getSockId(), Base.ConnectionCbArg);
00123         }
00124         catch (ESocketConnectionFailed &e)
00125         {
00126                 nlinfo ("HNETL4: can't connect now (%s)", e.what ());
00127         }
00128 }
00129 
00130 
00131 void RegistrationBroadcast (const std::string &name, TServiceId sid, const vector<CInetAddress> &addr)
00132 {
00133         nldebug("HNETL4: RegistrationBroadcast() of service %s-%hu", name.c_str (), (uint16)sid);
00134 
00135         // find if this new service is interesting
00136         for (CNetManager::ItBaseMap itbm = CNetManager::_BaseMap.begin (); itbm != CNetManager::_BaseMap.end (); itbm++)
00137         {
00138                 if ((*itbm).second.Type == CBaseStruct::Client && !(*itbm).second.NetBase[0]->connected())
00139                 {
00140                         if (name == (*itbm).first)
00141                         {
00142                                 // ok! it's cool, the service is here, go and connect to him!
00143 // ace warning don't work if more than one connection
00144                                 CNetManager::createConnection ((*itbm).second, addr[0], name);
00145                         }
00146                 }
00147                 else if ((*itbm).second.Type == CBaseStruct::Group)
00148                 {
00149                         // ok, it's a group, try to see if it wants this!
00150                         for (uint i = 0; i < (*itbm).second.ServiceNames.size (); i++)
00151                         {
00152                                 if ((*itbm).second.ServiceNames[i] == name)
00153                                 {
00154 // ace warning don't work if more than one connection
00155                                         CNetManager::createConnection ((*itbm).second, addr[0], name);
00156                                         break;
00157                                 }
00158                         }
00159                 }
00160         }
00161 
00162 }
00163 
00164 static void UnregistrationBroadcast (const std::string &name, TServiceId sid, const vector<CInetAddress> &addr)
00165 {
00166         nldebug("HNETL4: UnregistrationBroadcast() of service %s-%hu", name.c_str (), (uint16)sid);
00167 }
00168 
00169 void CNetManager::init (const CInetAddress *addr, CCallbackNetBase::TRecordingState rec )
00170 {
00171         if (addr == NULL) return;
00172 
00173         _RecordingState = rec;
00174 
00175         // connect to the naming service (may generate a ESocketConnectionFailed exception)
00176 
00177         vector<CInetAddress> laddr = CInetAddress::localAddresses();
00178         CNamingClient::connect( *addr, _RecordingState, laddr );
00179 
00180         // connect the callback to know when a new service comes in or goes down
00181         CNamingClient::setRegistrationBroadcastCallback (RegistrationBroadcast);
00182         CNamingClient::setUnregistrationBroadcastCallback (UnregistrationBroadcast);
00183 }
00184 
00185 void CNetManager::release ()
00186 {
00187         if (CNamingClient::connected ())
00188                 CNamingClient::disconnect ();
00189 
00190         for (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)
00191         {
00192                 for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
00193                 {
00194                         (*itbm).second.NetBase[i]->disconnect ();
00195                         delete (*itbm).second.NetBase[i];
00196                 }
00197         }
00198         _BaseMap.clear ();
00199 }
00200 
00201 void CNetManager::addServer (const std::string &serviceName, uint16 servicePort, bool external)
00202 {
00203         TServiceId sid = 0;
00204         addServer (serviceName, servicePort, sid, external);
00205 }
00206 
00207 void CNetManager::addServer (const std::string &serviceName, uint16 servicePort, TServiceId &sid, bool external)
00208 {
00209         nldebug ("HNETL4: Adding server '%s' in CNetManager", serviceName.c_str ());
00210         ItBaseMap itbm = find (serviceName);
00211 
00212         // check if it's a new server
00213         nlassert ((*itbm).second.NetBase.empty());
00214         
00215         CCallbackServer *cs = new CCallbackServer( _RecordingState, serviceName+string(".nmr") );
00216         (*itbm).second.NetBase.push_back (cs);
00217 
00218         (*itbm).second.Type = CBaseStruct::Server;
00219 
00220         // install the server
00221         
00222         cs->setConnectionCallback (nmNewConnection, (void*) &((*itbm).second));
00223         cs->CCallbackNetBase::setDisconnectionCallback (nmNewDisconnection, (void*) &((*itbm).second));
00224 
00225         if (servicePort == 0)
00226         {
00227                 nlassert (CNamingClient::connected ());
00228                 servicePort = CNamingClient::queryServicePort ();
00229         }
00230 
00231         cs->init (servicePort);
00232 
00233         // register the server to the naming service if we are connected to Naming Service
00234 
00235         if (CNamingClient::connected () && !external)
00236         {
00237                 //CInetAddress addr = CInetAddress::localHost ();
00238                 //addr.setPort (servicePort);
00239                 vector<CInetAddress> addr = CInetAddress::localAddresses();
00240                 for (uint i = 0; i < addr.size(); i++)
00241                         addr[i].setPort(servicePort);
00242 
00243                 if (sid == 0)
00244                 {
00245                         CNamingClient::registerService (serviceName, addr, sid);
00246                 }
00247                 else
00248                 {
00249                         CNamingClient::registerServiceWithSId (serviceName, addr, sid);
00250                 }
00251         }
00252         nlinfo ("HNETL4: Server '%s' added, registered and listen to port %hu", serviceName.c_str (), servicePort);
00253 }
00254 
00255 
00256 void CNetManager::addClient (const std::string &serviceName, const std::string &addr, bool autoRetry)
00257 {
00258         nldebug ("HNETL4: Adding client '%s' with addr '%s' in CNetManager", serviceName.c_str (), addr.c_str());
00259         ItBaseMap itbm = find (serviceName);
00260         
00261         // it's a new client, add the connection
00262         (*itbm).second.Type = CBaseStruct::ClientWithAddr;
00263         (*itbm).second.AutoRetry = autoRetry;
00264 
00265         if ((*itbm).second.ServiceNames.empty())
00266         {
00267                 (*itbm).second.ServiceNames.push_back(addr);
00268         }
00269         else
00270         {
00271                 (*itbm).second.ServiceNames[0] = addr;
00272         }
00273 
00274         nlassert ((*itbm).second.NetBase.size() < 2);
00275 
00276         createConnection ((*itbm).second, addr, serviceName);
00277 }
00278 
00279 
00280 void CNetManager::addClient (const std::string &serviceName)
00281 {
00282         nlassert (CNamingClient::connected ());
00283         nldebug ("HNETL4: Adding client '%s' in CNetManager", serviceName.c_str ());
00284         ItBaseMap itbm = find (serviceName);
00285         
00286         // check if it's a new client
00287         nlassert ((*itbm).second.NetBase.empty());
00288 
00289         CCallbackClient *cc = new CCallbackClient( _RecordingState, serviceName+string(".nmr") ); // ? - would not work if several clients with the same name
00290         (*itbm).second.NetBase.push_back (cc);
00291 
00292         (*itbm).second.Type = CBaseStruct::Client;
00293 
00294         cc->CCallbackNetBase::setDisconnectionCallback (nmNewDisconnection, (void*) &((*itbm).second));
00295 
00296         // find the service in the naming_service and connect if exists
00297         if (CNamingClient::lookupAndConnect (serviceName, *cc))
00298         {
00299                 // call the user that we are connected
00300                 if ((*itbm).second.ConnectionCallback != NULL)
00301                         (*itbm).second.ConnectionCallback (serviceName, cc->getSockId(), (*itbm).second.ConnectionCbArg);
00302         }
00303 }
00304 
00305 
00306 
00307 void CNetManager::addGroup (const std::string &groupName, const std::string &serviceName)
00308 {
00309         nlassert (CNamingClient::connected ());
00310         nldebug ("HNETL4: Adding '%s' to group '%s' in CNetManager", serviceName.c_str (), groupName.c_str());
00311         ItBaseMap itbm = find (groupName);
00312 
00313         (*itbm).second.Type = CBaseStruct::Group;
00314 
00315         // check if you don't already add this service in this group
00316         vector<string>::iterator it = std::find ((*itbm).second.ServiceNames.begin(), (*itbm).second.ServiceNames.end(), serviceName);
00317         nlassert (it == (*itbm).second.ServiceNames.end());
00318 
00319         (*itbm).second.ServiceNames.push_back(serviceName);
00320 
00321 
00322         // find the service in the naming_service and connect if exists
00323         vector<CInetAddress> addrs;
00324         CNamingClient::lookupAll (serviceName, addrs);
00325 
00326         // connect to all these services
00327         for (uint i = 0; i < addrs.size (); i++)
00328         {
00329                 createConnection ((*itbm).second, addrs[i], serviceName);
00330         }
00331 }
00332 
00333 
00334 
00335 NLMISC::CStringIdArray &CNetManager::getSIDA (const std::string &serviceName)
00336 {
00337         nldebug ("HNETL4: getSIDA() for service '%s'", serviceName.c_str ());
00338         ItBaseMap itbm = find (serviceName);
00339 
00340         // in case of group, we can return association only if there s only one service on it
00341         nlassert ((*itbm).second.NetBase.size() == 1);
00342 
00343         return (*itbm).second.NetBase[0]->getSIDA ();
00344 }
00345 
00346 void CNetManager::addCallbackArray (const std::string &serviceName, const TCallbackItem *callbackarray, NLMISC::CStringIdArray::TStringId arraysize)
00347 {
00348         nldebug ("HNETL4: addingCallabckArray() for service '%s'", serviceName.c_str ());
00349         ItBaseMap itbm = find (serviceName);
00350         for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
00351         {
00352 //              if ((*itbm).second.NetBase[i]->connected())
00353                 (*itbm).second.NetBase[i]->addCallbackArray (callbackarray, arraysize);
00354         }
00355 }
00356 
00357 void CNetManager::update (TTime timeout)
00358 {
00359 //      nldebug ("HNETL4: update()");
00360 
00361 //      sint64 p1 = CTime::getPerformanceTime ();
00362 
00363         TTime t0 = CTime::getLocalTime ();
00364 
00365         if (timeout > 0)
00366         {
00367                 if (_NextUpdateTime == 0)
00368                 {
00369                         _NextUpdateTime = t0 + timeout;
00370                 }
00371                 else
00372                 {
00373                         TTime err = t0 - _NextUpdateTime;
00374                         _NextUpdateTime += timeout;
00375 
00376                         // if we are too late, resync to the next value
00377                         while (err > timeout)
00378                         {
00379                                 err -= timeout;
00380                                 _NextUpdateTime += timeout;
00381                         }
00382                         
00383                         timeout -= err;
00384                         if (timeout < 0) timeout = 0;
00385                 }
00386         }
00387         
00388 //      sint64 p2 = CTime::getPerformanceTime ();
00389 
00390         while (true)
00391         {
00392                 for (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)
00393                 {
00394                         for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
00395                         {
00397                                 // we get and treat all messages in this connection
00398                                 (*itbm).second.NetBase[i]->update (0);
00399                                 if ((*itbm).second.NetBase[i]->connected())
00400                                 {
00401                                         // if connected, update
00402 //                                      (*itbm).second.NetBase[i]->update ();
00403                                 }
00404                                 else
00405                                 {
00406                                         static TTime lastTime = CTime::getLocalTime();
00407                                         if (CTime::getLocalTime() - lastTime > 5000)
00408                                         {
00409                                                 lastTime = CTime::getLocalTime();
00410 
00411                                                 // if not connected, try to connect ClientWithAddr
00412                                                 if ((*itbm).second.Type == CBaseStruct::ClientWithAddr && (*itbm).second.AutoRetry)
00413                                                 {
00414                                                         CCallbackClient *cc = dynamic_cast<CCallbackClient *>((*itbm).second.NetBase[i]);
00415                                                         try
00416                                                         {
00417                                                                 nlassert ((*itbm).second.ServiceNames.size()==1);
00418                                                                 cc->connect (CInetAddress((*itbm).second.ServiceNames[0]));
00419 
00420                                                                 if ((*itbm).second.ConnectionCallback != NULL)
00421                                                                         (*itbm).second.ConnectionCallback ((*itbm).second.Name, cc->getSockId(), (*itbm).second.ConnectionCbArg);
00422                                                         }
00423                                                         catch (ESocketConnectionFailed &e)
00424                                                         {
00425                                                                 // can't connect now, try later
00426                                                                 nlinfo("HNETL4: can't connect now to %s (reason: %s)", (*itbm).second.ServiceNames[0].c_str(), e.what());
00427                                                         }
00428                                                 }
00429                                         }
00430                                 }       
00431                         }
00432                 }
00433 
00434                 // If it's the end, don't nlSleep()
00435                 if (CTime::getLocalTime() - t0 > timeout)
00436                         break;
00437                 
00438                 // Enable windows multithreading before rescanning all connections
00439                 // slow down the layer H_BEFORE (CNetManager_update_nlSleep);
00440                 nlSleep (1);
00441                 // slow down the layer H_AFTER (CNetManager_update_nlSleep);
00442         }
00443 
00444 //      sint64 p3 = CTime::getPerformanceTime ();
00445 
00446         if (CNamingClient::connected ())
00447                 CNamingClient::update ();
00448 
00449 //      sint64 p4 = CTime::getPerformanceTime ();
00450 
00451 //      nlinfo("time : %f %f %f %d", CTime::ticksToSecond(p2-p1), CTime::ticksToSecond(p3-p2), CTime::ticksToSecond(p4-p3), timeout);
00452 }
00453 
00454 
00455 void CNetManager::send (const std::string &serviceName, const CMessage &buffer, TSockId hostid)
00456 {
00457         nldebug ("HNETL4: send for service '%s' message %s to %s", serviceName.c_str(), buffer.toString().c_str(), hostid->asString().c_str());
00458         ItBaseMap itbm = find (serviceName);
00459         for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
00460         {
00461                 if ((*itbm).second.NetBase[i]->connected())
00462                         (*itbm).second.NetBase[i]->send (buffer, hostid);
00463         }
00464 }
00465 
00466 CCallbackNetBase *CNetManager::getNetBase (const std::string &serviceName)
00467 {
00468         ItBaseMap itbm = find (serviceName);
00469         return (*itbm).second.NetBase[0];
00470 }
00471 
00472 void CNetManager::setConnectionCallback (const std::string &serviceName, TNetManagerCallback cb, void *arg)
00473 {
00474         nldebug ("HNETL4: setConnectionCallback() for service '%s'", serviceName.c_str ());
00475         ItBaseMap itbm = find (serviceName);
00476         (*itbm).second.ConnectionCallback = cb;
00477         (*itbm).second.ConnectionCbArg = arg;
00478 }
00479 
00480 void CNetManager::setDisconnectionCallback (const std::string &serviceName, TNetManagerCallback cb, void *arg)
00481 {
00482         nldebug ("HNETL4: setDisconnectionCallback() for service '%s'", serviceName.c_str ());
00483         ItBaseMap itbm = find (serviceName);
00484         (*itbm).second.DisconnectionCallback = cb;
00485         (*itbm).second.DisconnectionCbArg = arg;
00486 }
00487 
00488 
00489 CNetManager::ItBaseMap CNetManager::find (const std::string &serviceName)
00490 {
00491         // find the service or add it if not found
00492         pair<ItBaseMap, bool> p;
00493         p = _BaseMap.insert (make_pair (serviceName, CBaseStruct (serviceName)));
00494         return p.first;
00495 }
00496 
00497 uint64 CNetManager::getBytesSent ()
00498 {
00499         uint64 sent = 0;
00500         for (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)
00501         {
00502                 for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
00503                 {
00504                         sent += (*itbm).second.NetBase[i]->getBytesSent ();
00505                 }
00506         }
00507         return sent;
00508 }
00509 
00510 uint64 CNetManager::getBytesReceived ()
00511 {
00512         uint64 received = 0;
00513         for (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)
00514         {
00515                 for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
00516                 {
00517                         received += (*itbm).second.NetBase[i]->getBytesReceived ();
00518                 }
00519         }
00520         return received;
00521 }
00522 
00523 uint64 CNetManager::getSendQueueSize ()
00524 {
00525         uint64 val = 0;
00526         for (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)
00527         {
00528                 for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
00529                 {
00530                         val += (*itbm).second.NetBase[i]->getSendQueueSize ();
00531                 }
00532         }
00533         return val;
00534 }
00535 
00536 uint64 CNetManager::getReceiveQueueSize ()
00537 {
00538         uint64 val = 0;
00539         for (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)
00540         {
00541                 for (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)
00542                 {
00543                         val += (*itbm).second.NetBase[i]->getReceiveQueueSize ();
00544                 }
00545         }
00546         return val;
00547 }
00548 
00549 } // NLNET