# 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  

unified_network.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2002 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 #include "stdnet.h"
00027 
00028 #include "nel/net/unified_network.h"
00029 
00030 using namespace std;
00031 using namespace NLMISC;
00032 
00033 
00034 namespace NLNET {
00035 
00036 CLog test(CLog::LOG_INFO);
00037 CFileDisplayer fd;
00038 
00039 static uint ThreadCreator = 0;
00040 
00041 static const uint64 AppIdDeadConnection = 0xDEAD;
00042 
00043 #define AUTOCHECK_DISPLAY nlwarning
00044 //#define AUTOCHECK_DISPLAY CUnifiedNetwork::getInstance()->displayInternalTables (), nlerror
00045 
00046 // ace retirer ca
00047 static string allstuffs;
00048 
00049 //
00050 // Callbacks from NAMING SERVICE
00051 //
00052 
00053 // when a service registers
00054 void    uNetRegistrationBroadcast(const string &name, TServiceId sid, const vector<CInetAddress> &addr)
00055 {
00056         nldebug ("HNETL5: + naming %s-%hu '%s'", name.c_str(), (uint16)sid, vectorCInetAddressToString(addr).c_str ());
00057 
00058         allstuffs += "+naming "+name+"-"+toString(sid)+"\n";
00059         test.displayNL ("+naming %s-%hu", name.c_str (), (uint16)sid);
00060 
00061         CUnifiedNetwork *uni= CUnifiedNetwork::getInstance();
00062 
00063         if (uni->_SId == sid)
00064         {
00065                 allstuffs += "itsme!!!\n";
00066                 test.displayNL ("itsme!!!");
00067                 // it's me! don't add me!!!
00068                 return;
00069         }
00070 
00071         // add the unified connection
00072 
00073         if(sid >= uni->_IdCnx.size ())
00074                 uni->_IdCnx.resize (sid+1);
00075 
00076         if (uni->_IdCnx[sid].State == CUnifiedNetwork::CUnifiedConnection::NotUsed)
00077         {
00078                 uni->_IdCnx[sid] = CUnifiedNetwork::CUnifiedConnection(name, sid, false);
00079                 uni->_UsedConnection.push_back (sid);
00080         }
00081 
00082         if (!uni->_IdCnx[sid].ExtAddress.empty ()) AUTOCHECK_DISPLAY ("HNETL5: %s-%hu already inserted in the table with '%s'", name.c_str(), (uint16)sid, vectorCInetAddressToString (uni->_IdCnx[sid].ExtAddress).c_str ());
00083 
00084 
00085         // set the list of external addresses
00086 
00087         nlassert (!addr.empty());
00088 
00089         uni->_IdCnx[sid].ExtAddress = addr;
00090 
00091         // associate nid with ext address
00092         uni->_IdCnx[sid].setupNetworkAssociation (uni->_NetworkAssociations, uni->_DefaultNetwork);
00093 }
00094 
00095 // when a service unregisters
00096 void    uNetUnregistrationBroadcast(const string &name, TServiceId sid, const vector<CInetAddress> &addr)
00097 {
00098         nldebug ("HNETL5: - naming %s-%hu '%s'", name.c_str(), (uint16)sid, vectorCInetAddressToString (addr).c_str ());
00099 
00100         allstuffs += "-naming "+name+"-"+toString(sid)+"\n";
00101         test.displayNL ("-naming %s-%hu", name.c_str (), (uint16)sid);
00102 
00103         // get the service connection
00104         CUnifiedNetwork *uni = CUnifiedNetwork::getInstance();
00105 
00106         CUnifiedNetwork::CUnifiedConnection *uc = uni->getUnifiedConnection (sid);
00107         if (uc == 0) return;    // should never happen, the getUnifiedConnection() will generate a AUTOCHECK_DISPLAY
00108 
00109         // call the user callback
00110         CUnifiedNetwork::TNameMappedCallback::iterator  it2 = uni->_DownCallbacks.find(uc->ServiceName);
00111 
00112         if (it2 != uni->_DownCallbacks.end())
00113         {
00114                 // call it
00115                 TUnifiedNetCallback     cb = (*it2).second.first;
00116                 cb(uc->ServiceName, uc->ServiceId, (*it2).second.second);
00117         }
00118 
00119         for (uint c = 0; c < uni->_DownUniCallback.size (); c++)
00120         {
00121                 if (uni->_DownUniCallback[c].first != NULL)
00122                         uni->_DownUniCallback[c].first(uc->ServiceName, uc->ServiceId, uni->_DownUniCallback[c].second);
00123         }
00124 
00125         if(!uc->Connection.empty ())
00126         {
00127                 // set all connection to dead, now, all messages received on this socket will be ignored and closed
00128                 for (uint i = 0; i < uc->Connection.size (); ++i)
00129                 {
00130                         if (uc->Connection[i].valid())
00131                                 uc->Connection[i].setAppId (AppIdDeadConnection);
00132                 }
00133 
00134                 //
00135                 // It's the first connection that added the _NamedCnx so if there s no connection, no need to
00136                 // remove entry in _NamedCnx
00137                 //
00138 
00139                 uni->removeNamedCnx (uc->ServiceName, uc->ServiceId);
00140         }
00141 
00142         // remove the _UsedConnection
00143         bool found = false;
00144         for (vector<uint16>::iterator it = uni->_UsedConnection.begin (); it != uni->_UsedConnection.end(); it++)
00145         {
00146                 if (*it == uc->ServiceId)
00147                 {
00148                         found = true;
00149                         uni->_UsedConnection.erase (it);
00150                         break;
00151                 }
00152         }
00153         if (!found) AUTOCHECK_DISPLAY ("HNETL5: can't find the sid %hu in the _UsedConnection", uc->ServiceId);
00154 
00155         // reset the unified connection
00156         uc->reset ();
00157 }
00158 
00159 
00160 //
00161 // Callbacks from connection/disconnection services
00162 //
00163 
00164 void    uncbConnection(TSockId from, void *arg)
00165 {
00166         nlinfo ("HNETL5: + connec '%s'", from->asString().c_str());
00167 
00168         from->setAppId (AppIdDeadConnection);
00169 }
00170 
00171 void    uncbDisconnection(TSockId from, void *arg)
00172 {
00173         if(from->appId () == AppIdDeadConnection)
00174         {
00175                 nlinfo ("HNETL5: - connec '%s'", from->asString().c_str());
00176                 test.displayNL ("-connect dead conenction");
00177         }
00178         else
00179         {
00180                 CUnifiedNetwork *uni = CUnifiedNetwork::getInstance();
00181                 uint16                  sid = (uint16)from->appId();
00182                 CUnifiedNetwork::CUnifiedConnection *uc = uni->getUnifiedConnection (sid);
00183                 if (uc == 0)
00184                 {
00185                         nlinfo ("HNETL5: - connec '%s' sid %hu", from->asString().c_str(), sid);
00186                         test.displayNL ("-connect '%s' %hu", from->asString ().c_str (), sid);
00187                 }
00188                 else
00189                 {
00190                         nlinfo ("HNETL5: - connec '%s' %s-%hu", from->asString().c_str(), uc->ServiceName.c_str (), sid);
00191                         allstuffs += "-connect "+uc->ServiceName+"-"+toString(sid)+"\n";
00192                         test.displayNL ("-connect %s-%hu", uc->ServiceName.c_str (), (uint16)(uc->ServiceId));
00193 
00194                         if (uc->IsExternal)
00195                         {
00196                                 if (!uc->AutoRetry)
00197                                 {
00198                                         // If it s a external service with no auto retry, remove the connection
00199                                         
00200                                         // call the user callback
00201                                         CUnifiedNetwork::TNameMappedCallback::iterator  it2 = uni->_DownCallbacks.find(uc->ServiceName);
00202 
00203                                         if (it2 != uni->_DownCallbacks.end())
00204                                         {
00205                                                 // call it
00206                                                 TUnifiedNetCallback     cb = (*it2).second.first;
00207                                                 cb(uc->ServiceName, uc->ServiceId, (*it2).second.second);
00208                                         }
00209 
00210                                         for (uint c = 0; c < uni->_DownUniCallback.size (); c++)
00211                                         {
00212                                                 if (uni->_DownUniCallback[c].first != NULL)
00213                                                         uni->_DownUniCallback[c].first(uc->ServiceName, uc->ServiceId, uni->_DownUniCallback[c].second);
00214                                         }
00215 
00216                                         uni->removeNamedCnx (uc->ServiceName, uc->ServiceId);
00217         
00218                                         // remove the _UsedConnection
00219                                         bool found = false;
00220                                         for (vector<uint16>::iterator it = uni->_UsedConnection.begin (); it != uni->_UsedConnection.end(); it++)
00221                                         {
00222                                                 if (*it == uc->ServiceId)
00223                                                 {
00224                                                         found = true;
00225                                                         uni->_UsedConnection.erase (it);
00226                                                         break;
00227                                                 }
00228                                         }
00229                                         if (!found) AUTOCHECK_DISPLAY ("HNETL5: can't find the sid %hu in the _UsedConnection", uc->ServiceId);
00230 
00231                                         uc->reset ();
00232                                 }
00233                         }
00234                         else
00235                         {
00236                                 // reset the connection
00237                                 uint i;
00238                                 for (i = 0; i < uc->Connection.size (); i++)
00239                                 {
00240                                         if (uc->Connection[i].valid() && uc->Connection[i].CbNetBase->getSockId(uc->Connection[i].HostId) == from)
00241                                         {
00242                                                 if (uc->Connection[i].IsServerConnection)
00243                                                 {
00244                                                         // we have to remove the stuffs now because HostId will not be accessible later
00245                                                         uc->Connection[i].reset();
00246                                                 }
00247                                                 else
00248                                                 {
00249                                                         // if it s a client, we can't delete now because the callback client is currently in use
00250                                                         // only disconnect
00251                                                         if(uc->Connection[i].CbNetBase->connected ())
00252                                                         {
00253                                                                 uc->Connection[i].CbNetBase->disconnect (uc->Connection[i].HostId);
00254                                                         }
00255                                                 }
00256                                                 break;
00257                                         }
00258                                 }
00259                                 if (i == uc->Connection.size ())
00260                                 {
00261                                         AUTOCHECK_DISPLAY ("HNETL5: received a disconnection from a service but the connection is not in my list!");
00262                                 }
00263                         }
00264                 }
00265 
00266                 from->setAppId (AppIdDeadConnection);
00267         }
00268 }
00269 
00270 //
00271 // Callback from identication services
00272 //
00273 
00274 void    uncbServiceIdentification(CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
00275 {
00276         string          inSName;
00277         uint16          inSid;
00278 
00279         if (from->appId () != AppIdDeadConnection)
00280                 AUTOCHECK_DISPLAY ("HNETL5: received a connec ident from an unknown connection 0x%"NL_I64"X", from->appId ());
00281 
00282         // recover the service name and id
00283         msgin.serial(inSName);
00284         msgin.serial(inSid);
00285         uint8 pos;
00286         msgin.serial (pos);
00287         bool isExternal;
00288         msgin.serial (isExternal);
00289 
00290         nlinfo ("HNETL5: + connec ident '%s' %s-%hu pos %hu ext %d", from->asString().c_str(), inSName.c_str(), inSid, (uint16)pos, (uint8)isExternal);
00291         
00292         allstuffs += "+rconnect "+inSName+"-"+toString(inSid)+" pos "+toString((uint16)pos)+"\n";
00293         test.displayNL ("+rconnect %s-%hu pos %hu", inSName.c_str (), (uint16)inSid, (uint16)pos);
00294 
00295         if(isExternal)
00296         {
00297                 nlassert (pos == 0);
00298         }
00299 
00300         if (inSid == 0)
00301         {
00302                 if (isExternal)
00303                 {
00304                         inSid = CUnifiedNetwork::getInstance ()->_ExtSId++;
00305                         nlwarning ("HNETL5: Received a connection from a service with a SId 0, we give him the SId %d", inSid);
00306                 }
00307                 else
00308                 {
00309                         nlwarning ("HNETL5: Received a connection from a service with a SId 0 and wasn't external, disconnecting it");
00310                         netbase.disconnect();
00311                         return;
00312                 }
00313         }
00314 
00315         from->setAppId(inSid);
00316 
00317         // add a new connection to the list
00318         CUnifiedNetwork         *uni= CUnifiedNetwork::getInstance();
00319 
00320         if(inSid >= uni->_IdCnx.size ())
00321         {
00322                 uni->_IdCnx.resize (inSid+1);
00323         }
00324 
00325         switch(uni->_IdCnx[inSid].State)
00326         {
00327         case CUnifiedNetwork::CUnifiedConnection::NotUsed:              // add the new unified connection
00328                 uni->_IdCnx[inSid] = CUnifiedNetwork::CUnifiedConnection(inSName, inSid, isExternal);
00329                 uni->_UsedConnection.push_back (inSid);
00330                 break;
00331         default:
00332                 break;
00333         }
00334 
00335         if (uni->_IdCnx[inSid].IsExternal != isExternal)
00336         {
00337                 AUTOCHECK_DISPLAY ("HNETL5: Receive a connection that is not totally external %d %d", uni->_IdCnx[inSid].IsExternal, isExternal);
00338                 return;
00339         }
00340 
00341 
00342         // add the connection to the already inserted unified connection
00343         if (pos >= uni->_IdCnx[inSid].Connection.size ())
00344                 uni->_IdCnx[inSid].Connection.resize(pos+1);
00345         uni->_IdCnx[inSid].Connection[pos] = CUnifiedNetwork::CUnifiedConnection::TConnection(&netbase, from);
00346 
00347         // If the connection is external, we'll never receive the ExtAddress by the naming service, so add it manually
00348         if (isExternal)
00349         {
00350                 uni->_IdCnx[inSid].ExtAddress.push_back (netbase.hostAddress (from));
00351                 uni->_IdCnx[inSid].setupNetworkAssociation (uni->_NetworkAssociations, uni->_DefaultNetwork);
00352         }
00353 
00354 
00355         // todo ace temp to savoir comment c est possible ce cas la
00356         if (uni->_IdCnx[inSid].Connection.size() == 3)
00357         {
00358                 CUnifiedNetwork::CUnifiedConnection *uc = &uni->_IdCnx[inSid];
00359                 nlstop;
00360                 nlinfo ("ext addr %s", vectorCInetAddressToString (uc->ExtAddress).c_str ());
00361                 for(uint i = 0; i < uc->Connection.size(); i++)
00362                         nlinfo ("cnx %s", uc->Connection[i].HostId->asString ().c_str ());
00363                 nlinfo ("%s", allstuffs.c_str ());
00364         }
00365 
00366         // send the callback to the user with the first connection
00367         if (uni->_IdCnx[inSid].Connection.size () == 1)
00368         {
00369                 // insert the name in the map to be able to send message with the name
00370                 uni->addNamedCnx (inSName, inSid);
00371 
00372                 // now we warn the user
00373                 CUnifiedNetwork::TNameMappedCallback::iterator  it = uni->_UpCallbacks.find(inSName);
00374                 if (it != uni->_UpCallbacks.end())
00375                 {
00376                         // call it
00377                         TUnifiedNetCallback     cb = (*it).second.first;
00378                         cb(inSName, inSid, (*it).second.second);
00379                 }
00380 
00381                 for (uint c = 0; c < uni->_UpUniCallback.size (); c++)
00382                 {
00383                         if (uni->_UpUniCallback[c].first != NULL)
00384                                 uni->_UpUniCallback[c].first (inSName, inSid, uni->_UpUniCallback[c].second);
00385                 }
00386         }
00387 }
00388 
00389 // the callbacks wrapper
00390 void    uncbMsgProcessing(CMessage &msgin, TSockId from, CCallbackNetBase &netbase)
00391 {
00392         if (from->appId() == AppIdDeadConnection)
00393         {
00394                 AUTOCHECK_DISPLAY ("HNETL5: Receive a message from a dead connection");
00395                 return;
00396         }
00397 
00398         CUnifiedNetwork                                                                 *uni = CUnifiedNetwork::getInstance();
00399         uint16                                                                                  sid = (uint16)from->appId();
00400         CUnifiedNetwork::TMsgMappedCallback::iterator   itcb;
00401 
00402         itcb = uni->_Callbacks.find(msgin.getName());
00403         if (itcb == uni->_Callbacks.end())
00404         {
00405                 // the callback doesn't exist
00406                 nlwarning ("HNETL5: Can't find callback '%s' called by service %hu", msgin.getName().c_str(), sid);
00407         }
00408         else
00409         {
00410                 CUnifiedNetwork::CUnifiedConnection *uc = uni->getUnifiedConnection (sid);
00411 
00412                 if (uc == 0)
00413                 {
00414                         nlwarning ("HNETL5: Received a message from a service %hu that is not ready (bad appid? 0x%"NL_I64"X)", sid, from->appId ());
00415                         return;
00416                 }
00417                 if((*itcb).second == 0)
00418                 {
00419                         nlwarning ("HNETL5: Received message %s from a service %hu but the associated callback is NULL", msgin.getName ().c_str(), sid);
00420                         return;
00421                 }
00422                 (*itcb).second (msgin, uc->ServiceName, sid);
00423         }
00424 }
00425 
00426 
00427 TCallbackItem   unServerCbArray[] =
00428 {
00429         { "UN_SIDENT", uncbServiceIdentification }
00430 };
00431 
00432 
00433 //
00434 //
00435 //
00436 
00437 void    CUnifiedNetwork::init(const CInetAddress *addr, CCallbackNetBase::TRecordingState rec,
00438                                                           const string &shortName, uint16 port, TServiceId &sid)
00439 {
00440         //DebugLog->addNegativeFilter ("HNETL5");
00441 
00442         if (_Initialised)
00443         {
00444                 AUTOCHECK_DISPLAY ("HNETL5: Unified network layer already initialized");
00445                 return;
00446         }
00447 
00448         ThreadCreator = NLMISC::getThreadId();
00449 
00450         vector<CInetAddress> laddr = CInetAddress::localAddresses();
00451 
00452         _RecordingState = rec;
00453         _Name = shortName;
00454         _SId = sid;
00455         
00456         if (addr != 0)
00457                 _NamingServiceAddr = *addr;
00458 
00459         // if the address isn't 0, uses the naming service
00460         if (_NamingServiceAddr.isValid ())
00461         {
00462                 // connect the callback to know when a new service comes in or goes down
00463                 CNamingClient::setRegistrationBroadcastCallback(uNetRegistrationBroadcast);
00464                 CNamingClient::setUnregistrationBroadcastCallback(uNetUnregistrationBroadcast);
00465 
00466                 // connect to the naming service (may generate a ESocketConnectionFailed exception)
00467                 CNamingClient::connect(_NamingServiceAddr, _RecordingState, laddr);
00468 
00469                 if (port == 0)
00470                         port = CNamingClient::queryServicePort ();
00471         }
00472 
00473         // setup the server callback only if server port != 0, otherwise there's no server callback
00474         _ServerPort = port;
00475 
00476         if(_ServerPort != 0)
00477         {
00478                 nlassert (_CbServer == 0);
00479                 _CbServer = new CCallbackServer;
00480                 _CbServer->init(port);
00481                 _CbServer->addCallbackArray(unServerCbArray, 1);                                // the service ident callback
00482                 _CbServer->setDefaultCallback(uncbMsgProcessing);                               // the default callback wrapper
00483                 _CbServer->setConnectionCallback(uncbConnection, NULL);
00484                 _CbServer->setDisconnectionCallback(uncbDisconnection, NULL);
00485         }
00486         else
00487         {
00488                 nlinfo ("HNETL5: ServerPort is 0 so I don't create a CCallbackServer");
00489         }
00490 
00491         if (CNamingClient::connected())
00492         {
00493                 // register the service
00494                 for (uint i = 0; i < laddr.size(); i++)
00495                         laddr[i].setPort(_ServerPort);
00496 
00497                 if (_SId == 0)
00498                 {
00499                         CNamingClient::registerService(_Name, laddr, _SId);
00500                 }
00501                 else
00502                 {
00503                         CNamingClient::registerServiceWithSId(_Name, laddr, _SId);
00504                 }
00505 
00506                 sid = _SId;
00507 
00508                 nlinfo ("HNETL5: Server '%s' added, registered and listen to port %hu", _Name.c_str (), _ServerPort);
00509         }
00510 
00511         string fn = _Name+"_"+toString(_SId)+".log";
00512         fd.setParam (fn);
00513         test.addDisplayer (&fd);
00514         test.displayNL ("**************INIT***************");
00515 
00516         _Initialised = true;
00517 }
00518 
00519 void    CUnifiedNetwork::connect()
00520 {
00521         nlassertex(_Initialised == true, ("Try to CUnifiedNetwork::connect() whereas it is not initialised yet"));
00522 
00523         if (ThreadCreator != NLMISC::getThreadId()) nlwarning ("HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u", ThreadCreator, NLMISC::getThreadId());
00524 
00525 
00526         if (CNamingClient::connected())
00527         {
00528                 // get the services list
00529                 const list<CNamingClient::CServiceEntry>        &services = CNamingClient::getRegisteredServices();
00530 
00531                 // connects to the registered services
00532                 list<CNamingClient::CServiceEntry>::const_iterator      its;
00533 
00534                 // don't connect to itself
00535                 for (its = services.begin(); its != services.end(); ++its)
00536                 {
00537                         if (_SId != (*its).SId)
00538                         {
00539                                 // add service with name, address, ident, not external, service id, and not autoretry (obsolete)
00540                                 // we put the last true because the name callback should already inserted it by uNetRegistrationBroadcast()
00541                                 addService((*its).Name, (*its).Addr, true, false, (*its).SId, false, true);
00542                         }
00543                         else
00544                         {
00545                                 // don't process services received after mine because they'll connect to me
00546                                 break;
00547                         }
00548                 }
00549         }
00550 }
00551 
00552 void    CUnifiedNetwork::release()
00553 {
00554         if (!_Initialised)
00555                 return;
00556 
00557         if (ThreadCreator != NLMISC::getThreadId()) nlwarning ("HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u", ThreadCreator, NLMISC::getThreadId());
00558 
00559         // disconnect all clients
00560         if(_CbServer)
00561         {
00562                 _CbServer->disconnect(InvalidSockId);
00563                 delete _CbServer;
00564                 _CbServer = 0;
00565         }
00566 
00567         // disconnect all connections to servers
00568         for (uint i = 0; i<_IdCnx.size(); ++i)
00569         {
00570                 if (_IdCnx[i].State != CUnifiedNetwork::CUnifiedConnection::NotUsed)
00571                 {
00572                         for(uint j = 0 ; j < _IdCnx[i].Connection.size (); j++)
00573                         {
00574                                 if (_IdCnx[i].Connection[j].valid() && !_IdCnx[i].Connection[j].IsServerConnection)
00575                                 {
00576                                         if (_IdCnx[i].Connection[j].CbNetBase->connected ())
00577                                                 _IdCnx[i].Connection[j].CbNetBase->disconnect();
00578                                 
00579                                         delete _IdCnx[i].Connection[j].CbNetBase;
00580                                 }
00581                         }
00582                         _IdCnx[i].Connection.clear ();
00583                 }
00584         }
00585 
00586         // clear all other data
00587         _IdCnx.clear();
00588         _UsedConnection.clear ();
00589         _NamedCnx.clear();
00590         _UpCallbacks.clear();
00591         _DownCallbacks.clear();
00592         _Callbacks.clear();
00593 
00594         // disconnect the connection with the naming service
00595         if (CNamingClient::connected ())
00596                 CNamingClient::disconnect ();
00597 }
00598 
00599 void    CUnifiedNetwork::addService(const string &name, const CInetAddress &addr, bool sendId, bool external, uint16 sid, bool autoRetry, bool shouldBeAlreayInserted)
00600 {
00601         vector <CInetAddress> addrs;
00602         addrs.push_back (addr);
00603         addService (name, addrs, sendId, external, sid, autoRetry, shouldBeAlreayInserted);
00604 }
00605 
00606 void    CUnifiedNetwork::addService(const string &name, const vector<CInetAddress> &addr, bool sendId, bool external, uint16 sid, bool autoRetry, bool shouldBeAlreayInserted)
00607 {
00608         nlassertex(_Initialised == true, ("Try to CUnifiedNetwork::addService() whereas it is not initialised yet"));
00609 
00610         if (ThreadCreator != NLMISC::getThreadId()) nlwarning ("HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u", ThreadCreator, NLMISC::getThreadId());
00611 
00612         if (external)
00613                 sid = _ExtSId++;
00614 
00615         nlinfo("HNETL5: addService %s-%hu '%s'", name.c_str(), sid, vectorCInetAddressToString(addr).c_str());
00616 
00617         allstuffs += "addService "+name+"-"+toString(sid)+"\n";
00618         test.displayNL ("+service %s-%hu", name.c_str (), (uint16)sid);
00619 
00620         if (external && addr.size () != 1)
00621         {
00622                 AUTOCHECK_DISPLAY ("HNETL5: Can't add external service with more than one connection");
00623         }
00624 
00625         // add the entry in the unified connection table
00626 
00627         if (sid >= _IdCnx.size())
00628                 _IdCnx.resize(sid+1);
00629 
00630         CUnifiedConnection      *uc = &_IdCnx[sid];
00631 
00632         // at this point it s possible that the service already added in the _IdCnx by the uNetRegistrationBroadcast()
00633 
00634         if (shouldBeAlreayInserted && _IdCnx[sid].State == CUnifiedNetwork::CUnifiedConnection::NotUsed)  AUTOCHECK_DISPLAY ("HNETL5: the unified connection should already set by the naming reg broadcast and is not (%hu)", sid);
00635         if (!shouldBeAlreayInserted && _IdCnx[sid].State == CUnifiedNetwork::CUnifiedConnection::Ready)  AUTOCHECK_DISPLAY ("HNETL5: the unified connection should not already set but is (%hu)", sid);
00636 
00637         if (_IdCnx[sid].State == CUnifiedNetwork::CUnifiedConnection::NotUsed)
00638         {
00639                 *uc = CUnifiedConnection(name, sid, external);
00640                 _UsedConnection.push_back (sid);
00641         }
00642         else
00643         {
00644                 // If the entry already set, check that all is correct
00645                 if (name != uc->ServiceName) AUTOCHECK_DISPLAY ("HNETL5: name are different in addService %s %s", name.c_str (), uc->ServiceName.c_str ());
00646                 if (sid != uc->ServiceId) AUTOCHECK_DISPLAY ("HNETL5: sid are different in addService %hu %hu", sid, uc->ServiceId);
00647                 if (addr != uc->ExtAddress) AUTOCHECK_DISPLAY ("HNETL5: external addr are different in addService '%s' '%s'", vectorCInetAddressToString(addr).c_str(), vectorCInetAddressToString(uc->ExtAddress).c_str ());
00648         }
00649         uc->AutoRetry = autoRetry;
00650         uc->SendId = sendId;
00651         uc->ExtAddress = addr;
00652         nlassert (!addr.empty());
00653 
00654         // associate nid with ext address
00655         uc->setupNetworkAssociation (_NetworkAssociations, _DefaultNetwork);
00656 
00657         // connect to all connection
00658         bool    connectSuccess;
00659         
00660         if (uc->Connection.size () < addr.size ())
00661         {
00662                 uc->Connection.resize (addr.size ());
00663         }
00664 
00665         vector<CInetAddress> laddr = CInetAddress::localAddresses();
00666 
00667         for (uint i = 0; i < addr.size(); i++)
00668         {
00669                 // first we have to look if we have a network that can established the connection
00670 
00671                 uint j = 0;
00672                 // it s 127.0.0.1, it s ok
00673                 if (!addr[i].is127001 ())
00674                 {
00675                         for (j = 0; j < laddr.size (); j++)
00676                         {
00677                                 if (laddr[j].internalNetAddress () == addr[i].internalNetAddress ())
00678                                 {
00679                                         // it's ok, we can try
00680                                         break;
00681                                 }
00682                         }
00683 
00684                         // If we don't found a valid network, we'll try with the first one.
00685                         // It's happen, for example, when you try to connect to a service that is not in the network but use IP translation
00686                         if (j == laddr.size ())
00687                         {
00688                                 nlwarning ("I can't access '%s' because I haven't a net card on this network, we'll use the first network", addr[i].asString ().c_str ());
00689                                 j = 0;
00690                         }
00691                 }
00692 
00693                 // create a new connection with the service, setup callback and connect
00694                 CCallbackClient *cbc = new CCallbackClient();
00695                 cbc->setDisconnectionCallback(uncbDisconnection, NULL);
00696                 cbc->setDefaultCallback(uncbMsgProcessing);
00697                 cbc->getSockId()->setAppId(sid);
00698 
00699                 try
00700                 {
00701                         cbc->connect(addr[i]);
00702                         connectSuccess = true;
00703                         
00704                         allstuffs += "+lconnect "+name+"-"+toString(sid)+"\n";
00705                         test.displayNL ("+lconnect %s-%hu", name.c_str (), (uint16)sid);
00706                 }
00707                 catch (ESocketConnectionFailed &e)
00708                 {
00709                         nlwarning ("HNETL5: can't connect to %s (sid %u) now (%s) '%s'", name.c_str(), sid, e.what (), addr[i].asString ().c_str());
00710                         connectSuccess = false;
00711 
00712                         allstuffs += "+lconnect failed "+name+"-"+toString((uint16)sid)+"\n";
00713                         test.displayNL ("+lconnect failed %s-%hu", name.c_str (), (uint16)sid);
00714                 }
00715 
00716                 if (!connectSuccess && !autoRetry)
00717                 {
00718                         nlwarning ("HNETL5: Can't add service because no retry and can't connect");
00719                         delete cbc;
00720                 }
00721                 else
00722                 {
00723                         uc->Connection[i] = CUnifiedNetwork::CUnifiedConnection::TConnection(cbc);
00724 
00725                         nlinfo ("%s", allstuffs.c_str ());
00726                 }
00727 
00728                 if (connectSuccess && sendId)
00729                 {
00730                         // send identification to the service
00731                         CMessage        msg("UN_SIDENT");
00732                         msg.serial(_Name);
00733                         uint16          ssid = _SId;
00734                         if (uc->IsExternal)
00735                         {
00736                                 // in the case that the service is external, we can't send our sid because the external service can
00737                                 // have other connectin with the same sid (for example, LS can have 2 WS with same sid => sid = 0 and leave
00738                                 // the other side to find a good number
00739                                 ssid = 0;
00740                         }
00741                         msg.serial(ssid);       // serializes a 16 bits service id
00742                         uint8 pos = j;
00743                         msg.serial(pos);        // send the position in the connection table
00744                         msg.serial (uc->IsExternal);
00745                         cbc->send (msg);
00746                 }
00747         }
00748 
00749         if (addr.size () != uc->Connection.size())
00750         {
00751                 nlwarning ("HNETL5: Can't connect to all connections to the service %d/%d", addr.size (), uc->Connection.size());
00752         }
00753 
00754         bool cntok = false;
00755         for (uint j = 0; j < uc->Connection.size(); j++)
00756         {
00757                 if (uc->Connection[j].CbNetBase != NULL)
00758                 {
00759                         if (uc->Connection[j].CbNetBase->connected ())
00760                         {
00761                                 cntok = true;
00762                                 break;
00763                         }
00764                 }
00765         }
00766 
00767         if (cntok)
00768         {
00769                 // add the name only if at least one connection is ok
00770                 addNamedCnx (name, sid);
00771 
00772                 // call the connection callback associated to this service
00773                 TNameMappedCallback::iterator   itcb = _UpCallbacks.find(name);
00774                 if (itcb != _UpCallbacks.end() && (*itcb).second.first != NULL)
00775                 {
00776                         TUnifiedNetCallback     cb = (*itcb).second.first;
00777                         cb(name, sid, (*itcb).second.second);
00778                 }
00779 
00780                 if (!external)
00781                 {
00782                         for (uint i = 0; i < _UpUniCallback.size (); i++)
00783                         {
00784                                 if (_UpUniCallback[i].first != NULL)
00785                                         _UpUniCallback[i].first (name, sid, _UpUniCallback[i].second);
00786                         }
00787                 }
00788         }
00789 
00790         nldebug ("HNETL5: addService was successful");
00791 }
00792 //
00793 //
00794 //
00795 
00796 #define TIME_BLOCK(tick, instr) \
00797 { \
00798         TTicks  _time_block_before = CTime::getPerformanceTime(); \
00799         instr ; \
00800         TTicks  _time_block_after = CTime::getPerformanceTime(); \
00801         tick += (_time_block_after - _before); \
00802 }
00803 
00804 void    CUnifiedNetwork::update(TTime timeout)
00805 {
00806         nlassertex(_Initialised == true, ("Try to CUnifiedNetwork::update() whereas it is not initialised yet"));
00807 
00808         if (ThreadCreator != NLMISC::getThreadId()) nlwarning ("HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u", ThreadCreator, NLMISC::getThreadId());
00809 
00810         bool    enableRetry;    // true every 5 seconds to reconnect if necessary
00811 
00812         // Compute the real timeout based on the next update timeout
00813         TTime t0 = CTime::getLocalTime ();
00814 
00815         if (timeout > 0)
00816         {
00817                 if (_NextUpdateTime == 0)
00818                 {
00819                         _NextUpdateTime = t0 + timeout;
00820                 }
00821                 else
00822                 {
00823                         TTime err = t0 - _NextUpdateTime;
00824                         _NextUpdateTime += timeout;
00825 
00826                         // if we are too late, resync to the next value
00827                         while (err > timeout)
00828                         {
00829                                 err -= timeout;
00830                                 _NextUpdateTime += timeout;
00831                         }
00832                         
00833                         timeout -= err;
00834                         if (timeout < 0) timeout = 0;
00835                 }
00836         }
00837 
00838         // check if we need to retry to connect to the client
00839         if ((enableRetry = (t0-_LastRetry > 5000)))
00840                 _LastRetry = t0;
00841 
00842         // Try to reconnect to the naming service if connection lost
00843         if (_NamingServiceAddr.isValid ())
00844         {
00845                 if (CNamingClient::connected ())
00846                 {
00847                         CNamingClient::update ();
00848                 }
00849                 else if (enableRetry)
00850                 {
00851                         try
00852                         {
00853                                 vector<CInetAddress> laddr = CInetAddress::localAddresses();
00854                                 CNamingClient::connect (_NamingServiceAddr, _RecordingState, laddr);
00855                                 // re-register the service
00856                                 for (uint i = 0; i < laddr.size(); i++)
00857                                         laddr[i].setPort(_ServerPort);
00858                                 CNamingClient::resendRegisteration (_Name, laddr, _SId);
00859                         }
00860                         catch (ESocketConnectionFailed &)
00861                         {
00862                                 nlwarning ("HNETL5: Could not connect to the Naming Service (%s). Retrying in a few seconds...", _NamingServiceAddr.asString().c_str());
00863                         }
00864                 }
00865         }
00866 
00867         while (true)
00868         {
00869                 // update all server connections
00870                 if (_CbServer)
00871                         _CbServer->update(0);
00872 
00873                 // update all client connections
00874                 for (uint k = 0; k<_UsedConnection.size(); ++k)
00875                 {
00876                         CUnifiedConnection &uc = _IdCnx[_UsedConnection[k]];
00877                         nlassert (uc.State == CUnifiedNetwork::CUnifiedConnection::Ready);
00878                         for (uint j = 0; j < uc.Connection.size (); j++)
00879                         {
00880                                 if (!uc.Connection[j].valid())
00881                                         continue;
00882 
00883                                 if (uc.Connection[j].IsServerConnection)
00884                                         continue;
00885 
00886                                 if (uc.Connection[j].CbNetBase->connected ())
00887                                 {
00888                                         uc.Connection[j].CbNetBase->update(0);
00889                                 }
00890                                 else if (enableRetry && uc.AutoRetry)
00891                                 {
00892                                         try
00893                                         {
00894                                                 CCallbackClient *cbc = (CCallbackClient *)uc.Connection[j].CbNetBase;
00895                                                 cbc->connect(uc.ExtAddress[j]);
00896                                                 uc.Connection[j].CbNetBase->getSockId()->setAppId(uc.ServiceId);
00897                                                 nlinfo ("HNETL5: reconnection to %s-%hu success", uc.ServiceName.c_str(), uc.ServiceId);
00898 
00899 
00900                                                 // add the name only if at least one connection is ok
00901                                                 if (!haveNamedCnx (uc.ServiceName, uc.ServiceId))
00902                                                         addNamedCnx (uc.ServiceName, uc.ServiceId);
00903 
00904                                                 // resend the identification is necessary
00905                                                 if (uc.SendId)
00906                                                 {
00907                                                         // send identification to the service
00908                                                         CMessage        msg("UN_SIDENT");
00909                                                         msg.serial(_Name);
00910 
00911                                                         uint16          ssid = _SId;
00912                                                         msg.serial(ssid);       // serializes a 16 bits service id
00913                                                         uint8 pos = j;
00914                                                         msg.serial(pos);        // send the position in the connection table
00915                                                         msg.serial (uc.IsExternal);
00916                                                         uc.Connection[j].CbNetBase->send (msg, uc.Connection[j].HostId);
00917                                                 }
00918 
00919                                                 // call the user callback
00920                                                 CUnifiedNetwork::TNameMappedCallback::iterator  it = _UpCallbacks.find(uc.ServiceName);
00921                                                 if (it != _UpCallbacks.end())
00922                                                 {
00923                                                         // call it
00924                                                         TUnifiedNetCallback     cb = (*it).second.first;
00925                                                         cb(uc.ServiceName, uc.ServiceId, (*it).second.second);
00926                                                 }
00927 
00928                                                 for (uint c = 0; c < _UpUniCallback.size (); c++)
00929                                                 {
00930                                                         if (_UpUniCallback[c].first != NULL)
00931                                                                 _UpUniCallback[c].first (uc.ServiceName, uc.ServiceId, _UpUniCallback[c].second);
00932                                                 }
00933 
00934                                         }
00935                                         catch (ESocketConnectionFailed &e)
00936                                         {
00937                                                 nlinfo ("HNETL5: can't connect to %s-%hu now (%s)", uc.ServiceName.c_str(), uc.ServiceId, e.what ());
00938                                         }
00939                                 }
00940                         }
00941                 }
00942 
00943                 enableRetry = false;
00944 
00945                 // If it's the end, don't nlSleep()
00946                 if (CTime::getLocalTime() - t0 > timeout)
00947                         break;
00948                 
00949                 // Enable windows multithreading before rescanning all connections
00950                 nlSleep (1);
00951         }
00952 
00953         autoCheck();
00954 }
00955 
00956 //
00957 //
00958 //
00959 uint8 CUnifiedNetwork::findConnectionId (uint16 sid, uint8 nid)
00960 {
00961         if (_IdCnx[sid].Connection.size () == 0)
00962         {
00963                 nlwarning ("HNETL5: Can't send message to %s because no connection are available", _IdCnx[sid].ServiceName.c_str ());
00964                 return 0xFF;
00965         }
00966 
00967         // by default, connection id will be the default one
00968         uint8 connectionId = _IdCnx[sid].DefaultNetwork;
00969 
00970         if (nid == 0xFF)
00971         {
00972                 // it s often appen because they didn't set a good network configuration, so it s in debug to disable it easily
00973                 //nldebug ("HNETL5: nid %hu, will use the default connection %hu", (uint16)nid, (uint16)connectionId);
00974         }
00975         else if (nid >= _IdCnx[sid].NetworkConnectionAssociations.size())
00976         {
00977                 nlwarning ("HNETL5: No net association for nid %hu, use the default connection %hu", (uint16)nid, (uint16)connectionId);
00978         }
00979         else
00980         {
00981                 if (_IdCnx[sid].NetworkConnectionAssociations[nid] >= _IdCnx[sid].Connection.size ())
00982                 {
00983                         nlwarning ("HNETL5: Can't send message to %s because nid %d point on a bad connection (%d and only have %d cnx), use default connection", _IdCnx[sid].ServiceName.c_str (), nid, connectionId, _IdCnx[sid].Connection.size ());
00984                 }
00985                 else
00986                 {
00987                         connectionId = _IdCnx[sid].NetworkConnectionAssociations[nid];
00988                 }
00989         }
00990 
00991         if (connectionId >= _IdCnx[sid].Connection.size() || !_IdCnx[sid].Connection[connectionId].valid() || !_IdCnx[sid].Connection[connectionId].CbNetBase->connected())
00992         {
00993                 // there's a problem with the selected connectionID, so try to find a valid one
00994                 nlwarning ("HNETL5: Can't find selected connection id %hu to send message to %s because connection is not valid or connected, find a valid connection id", (uint16)connectionId, _IdCnx[sid].ServiceName.c_str ());
00995 
00996                 for (connectionId = 0; connectionId < _IdCnx[sid].Connection.size(); connectionId++)
00997                 {
00998                         if (_IdCnx[sid].Connection[connectionId].valid() && _IdCnx[sid].Connection[connectionId].CbNetBase->connected())
00999                         {
01000                                 // we found one at last, use this one
01001                                 //nldebug ("HNETL5: Ok, we found a valid connectionid, use %hu",  (uint16)connectionId);
01002                                 break;
01003                         }
01004                 }
01005 
01006                 if (connectionId == _IdCnx[sid].Connection.size())
01007                 {
01008                         nlwarning ("HNETL5: Can't send message to %s because default connection is not exist, valid or connected", _IdCnx[sid].ServiceName.c_str ());
01009                         return 0xFF;
01010                 }
01011         }
01012         return connectionId;
01013 }
01014 
01015 
01016 //
01017 //
01018 //
01019 
01020 bool    CUnifiedNetwork::send(const string &serviceName, const CMessage &msgout, uint8 nid)
01021 {
01022         nlassertex(_Initialised == true, ("Try to CUnifiedNetwork::send(const string&, const CMessage&) whereas it is not initialised yet"));
01023 
01024         if (ThreadCreator != NLMISC::getThreadId()) nlwarning ("HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u", ThreadCreator, NLMISC::getThreadId());
01025 
01026         TNameMappedConnection::const_iterator                                                           it;
01027         pair<TNameMappedConnection::const_iterator,TNameMappedConnection::const_iterator>       range;
01028         range = _NamedCnx.equal_range(serviceName);
01029 
01030         bool found = false;
01031         if (range.first != _NamedCnx.end())
01032         {
01033                 for (it=range.first; it!=range.second; ++it)
01034                 {
01035                         uint16  sid = (*it).second;
01036                         if (sid >= _IdCnx.size () || _IdCnx[sid].State != CUnifiedNetwork::CUnifiedConnection::Ready)
01037                         {
01038                                 // It often happen when the service is down (connection broke and the naming not already say that it s down)
01039                                 // In this case, just warn
01040                                 nlwarning ("HNETL5: Can't send to the service '%s' because it was in the _NamedCnx but not in _IdCnx (means that the service is down)", serviceName.c_str ());
01041                                 return false;
01042                         }
01043 
01044                         found = true;
01045 
01046                         uint8 connectionId = findConnectionId (sid, nid);
01047                         if (connectionId == 0xff)       // failed
01048                         {
01049                                 nlwarning ("HNETL5: Can't send message to %hu because no connection available", sid);
01050                                 found = false;
01051                                 continue;
01052                         }
01053 
01054                         //nldebug ("HNETL5: send message to %s using nid %d cnx %d / %s", serviceName.c_str (), nid, connectionId, connectionId<_IdCnx[sid].ExtAddress.size ()?_IdCnx[sid].ExtAddress[connectionId].asString().c_str():"???");
01055                         _IdCnx[sid].Connection[connectionId].CbNetBase->send (msgout, _IdCnx[sid].Connection[connectionId].HostId);
01056                 }
01057         }
01058 
01059         if (!found)
01060                 nlwarning ("HNETL5: can't find service %s to send message %s", serviceName.c_str(), msgout.getName().c_str());
01061 
01062         return found;
01063 }
01064 
01065 bool    CUnifiedNetwork::send(uint16 sid, const CMessage &msgout, uint8 nid)
01066 {
01067         nlassertex(_Initialised == true, ("Try to CUnifiedNetwork::send(uint16, const CMessage&) whereas it is not initialised yet"));
01068 
01069         if (ThreadCreator != NLMISC::getThreadId()) nlwarning ("HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u", ThreadCreator, NLMISC::getThreadId());
01070 
01071         if (sid >= _IdCnx.size () || _IdCnx[sid].State != CUnifiedNetwork::CUnifiedConnection::Ready)
01072         {
01073                 // happen when trying to send a message to an unknown service id
01074                 nlwarning ("HNETL5: Can't send to the service '%hu' because not in _IdCnx", sid);
01075                 return false;
01076         }
01077 
01078         uint8 connectionId = findConnectionId (sid, nid);
01079         if (connectionId == 0xff)       // failed
01080         {
01081                 nlwarning ("HNETL5: Can't send to the service '%hu' because no connection available", sid);
01082                 return false;
01083         }
01084 
01085         _IdCnx[sid].Connection[connectionId].CbNetBase->send (msgout, _IdCnx[sid].Connection[connectionId].HostId);
01086         return true;
01087 }
01088 
01089 void    CUnifiedNetwork::send(const CMessage &msgout, uint8 nid)
01090 {
01091         nlassertex(_Initialised == true, ("Try to CUnifiedNetwork::send(const CMessage&) whereas it is not initialised yet"));
01092 
01093         if (ThreadCreator != NLMISC::getThreadId()) nlwarning ("HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u", ThreadCreator, NLMISC::getThreadId());
01094 
01095         uint    i;
01096         for (i=0; i<_IdCnx.size(); ++i)
01097         {
01098                 if (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::Ready)
01099                 {
01100                         uint8 connectionId = findConnectionId (i, nid);
01101                         if (connectionId == 0xff)       // failed
01102                         {
01103                                 nlwarning ("HNETL5: Can't send message to %u because no connection available", i);
01104                                 continue;
01105                         }
01106 
01107                         _IdCnx[i].Connection[connectionId].CbNetBase->send (msgout, _IdCnx[i].Connection[connectionId].HostId);
01108                 }
01109         }
01110 }
01111 
01112 
01113 //
01114 //
01115 //
01116 
01117 void    CUnifiedNetwork::addCallbackArray (const TUnifiedCallbackItem *callbackarray, CStringIdArray::TStringId arraysize)
01118 {
01119         uint    i;
01120 
01121         for (i=0; i<(uint)arraysize; ++i)
01122                 _Callbacks.insert(make_pair(string(callbackarray[i].Key),callbackarray[i].Callback));
01123 }
01124 
01125 
01126 void    CUnifiedNetwork::setServiceUpCallback (const string &serviceName, TUnifiedNetCallback cb, void *arg, bool back)
01127 {
01128         if (serviceName == "*")
01129         {
01130                 nlassert (cb != NULL);
01131                 if (back)
01132                         _UpUniCallback.push_back (make_pair(cb, arg));
01133                 else
01134                         _UpUniCallback.insert (_UpUniCallback.begin(), make_pair(cb, arg));
01135 
01136                 return;
01137         }
01138 
01139         TNameMappedCallback::iterator   it = _UpCallbacks.find(serviceName);
01140         if (it == _UpCallbacks.end())
01141         {
01142                 TCallbackArgItem        ncb;
01143                 ncb.first = NULL;
01144                 ncb.second = NULL;
01145                 it = _UpCallbacks.insert(make_pair(serviceName, ncb));
01146         }
01147 
01148         (*it).second.first = cb;
01149         (*it).second.second = arg;
01150 }
01151 
01152 void    CUnifiedNetwork::setServiceDownCallback (const string &serviceName, TUnifiedNetCallback cb, void *arg, bool back)
01153 {
01154         if (serviceName == "*")
01155         {
01156                 nlassert (cb != NULL);
01157                 if (back)
01158                         _DownUniCallback.push_back (make_pair(cb, arg));
01159                 else
01160                         _DownUniCallback.insert (_DownUniCallback.begin(), make_pair(cb, arg));
01161 
01162                 return;
01163         }
01164 
01165         TNameMappedCallback::iterator   it = _DownCallbacks.find(serviceName);
01166         if (it == _DownCallbacks.end())
01167         {
01168                 TCallbackArgItem        ncb;
01169                 ncb.first = NULL;
01170                 ncb.second = NULL;
01171                 it = _DownCallbacks.insert(make_pair(serviceName, ncb));
01172         }
01173 
01174         (*it).second.first = cb;
01175         (*it).second.second = arg;
01176 }
01177 
01178 //
01179 //
01180 //
01181 
01182 uint64 CUnifiedNetwork::getBytesSent ()
01183 {
01184         uint64  sent = 0;
01185         uint    j;
01186 
01187         for (vector<uint16>::iterator it = _UsedConnection.begin (); it != _UsedConnection.end(); it++)
01188         {
01189                 if (_IdCnx[(*it)].State == CUnifiedNetwork::CUnifiedConnection::Ready)
01190                         for (j=0; j<_IdCnx[(*it)].Connection.size (); ++j)
01191                                 if(_IdCnx[(*it)].Connection[j].valid () && !_IdCnx[(*it)].Connection[j].IsServerConnection)
01192                                         sent += _IdCnx[(*it)].Connection[j].CbNetBase->getBytesSent();
01193         }
01194 
01195 /*      for (i=0; i<_IdCnx.size(); ++i)
01196                 if (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::Ready)
01197                         for (j=0; j<_IdCnx[i].Connection.size (); ++j)
01198                                 if(_IdCnx[i].Connection[j].valid () && !_IdCnx[i].Connection[j].IsServerConnection)
01199                                         sent += _IdCnx[i].Connection[j].CbNetBase->getBytesSent();
01200 */
01201         if(_CbServer)
01202                 sent += _CbServer->getBytesSent();
01203         return sent;
01204 }
01205 
01206 uint64 CUnifiedNetwork::getBytesReceived ()
01207 {
01208         uint64  received = 0;
01209         uint    j;
01210 
01211         for (vector<uint16>::iterator it = _UsedConnection.begin (); it != _UsedConnection.end(); it++)
01212         {
01213                 if (_IdCnx[(*it)].State == CUnifiedNetwork::CUnifiedConnection::Ready)
01214                         for (j=0; j<_IdCnx[(*it)].Connection.size (); ++j)
01215                                 if(_IdCnx[(*it)].Connection[j].valid () && !_IdCnx[(*it)].Connection[j].IsServerConnection)
01216                                         received += _IdCnx[(*it)].Connection[j].CbNetBase->getBytesReceived();
01217         }
01218         
01219 /*      for (i=0; i<_IdCnx.size(); ++i)
01220                 if (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::Ready)
01221                         for (j=0; j<_IdCnx[i].Connection.size (); ++j)
01222                                 if(_IdCnx[i].Connection[j].valid () && !_IdCnx[i].Connection[j].IsServerConnection)
01223                                         received += _IdCnx[i].Connection[j].CbNetBase->getBytesReceived();
01224 */
01225         if (_CbServer)
01226                 received += _CbServer->getBytesReceived();
01227         return received;
01228 }
01229 
01230 uint64 CUnifiedNetwork::getSendQueueSize ()
01231 {
01232         uint64  sent = 0;
01233         uint    j;
01234 
01235         for (vector<uint16>::iterator it = _UsedConnection.begin (); it != _UsedConnection.end(); it++)
01236         {
01237                 if (_IdCnx[(*it)].State == CUnifiedNetwork::CUnifiedConnection::Ready)
01238                         for (j=0; j<_IdCnx[(*it)].Connection.size (); ++j)
01239                                 if(_IdCnx[(*it)].Connection[j].valid () && !_IdCnx[(*it)].Connection[j].IsServerConnection)
01240                                         sent += _IdCnx[(*it)].Connection[j].CbNetBase->getSendQueueSize();
01241         }
01242 
01243 /*      for (i=0; i<_IdCnx.size(); ++i)
01244                 if (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::Ready)
01245                         for (j=0; j<_IdCnx[i].Connection.size (); ++j)
01246                                 if(_IdCnx[i].Connection[j].valid () && !_IdCnx[i].Connection[j].IsServerConnection)
01247                                         sent += _IdCnx[i].Connection[j].CbNetBase->getSendQueueSize();
01248 */
01249         if (_CbServer)
01250                 sent += _CbServer->getSendQueueSize();
01251         return sent;
01252 }
01253 
01254 uint64 CUnifiedNetwork::getReceiveQueueSize ()
01255 {
01256         uint64  received = 0;
01257         uint    j;
01258 
01259         for (vector<uint16>::iterator it = _UsedConnection.begin (); it != _UsedConnection.end(); it++)
01260         {
01261                 if (_IdCnx[(*it)].State == CUnifiedNetwork::CUnifiedConnection::Ready)
01262                         for (j=0; j<_IdCnx[(*it)].Connection.size (); ++j)
01263                                 if(_IdCnx[(*it)].Connection[j].valid () && !_IdCnx[(*it)].Connection[j].IsServerConnection)
01264                                         received += _IdCnx[(*it)].Connection[j].CbNetBase->getReceiveQueueSize();
01265         }
01266 
01267 /*      for (i=0; i<_IdCnx.size(); ++i)
01268                 if (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::Ready)
01269                         for (j=0; j<_IdCnx[i].Connection.size (); ++j)
01270                                 if(_IdCnx[i].Connection[j].valid () && !_IdCnx[i].Connection[j].IsServerConnection)
01271                                         received += _IdCnx[i].Connection[j].CbNetBase->getReceiveQueueSize();
01272 */
01273         if (_CbServer)
01274                 received += _CbServer->getReceiveQueueSize();
01275         return received;
01276 }
01277 
01278 CCallbackNetBase        *CUnifiedNetwork::getNetBase(const std::string &name, TSockId &host, uint8 nid)
01279 {
01280         nlassertex(_Initialised == true, ("Try to CUnifiedNetwork::getNetBase() whereas it is not initialised yet"));
01281 
01282         if (ThreadCreator != NLMISC::getThreadId()) nlwarning ("HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u", ThreadCreator, NLMISC::getThreadId());
01283 
01284         sint    count = _NamedCnx.count(name);
01285 
01286         if (count <= 0)
01287         {
01288                 nlwarning ("HNETL5: couldn't access the service %s", name.c_str());
01289                 host = InvalidSockId;
01290                 return NULL;
01291         }
01292         else if (count > 1)
01293         {
01294                 nlwarning ("HNETL5: %d services %s to getNetBase, returns the first valid", count, name.c_str());
01295         }
01296 
01297         TNameMappedConnection::const_iterator   itnmc = _NamedCnx.find(name);
01298 
01299         uint8 connectionId = findConnectionId ((*itnmc).second, nid);
01300         if (connectionId == 0xff)       // failed
01301         {
01302                 nlwarning ("Can't getNetBase %s because no connection available", name.c_str());
01303                 host = InvalidSockId;
01304                 return NULL;
01305         }
01306 
01307         host = _IdCnx[(*itnmc).second].Connection[connectionId].HostId;
01308         return _IdCnx[(*itnmc).second].Connection[connectionId].CbNetBase;
01309 }
01310 
01311 CCallbackNetBase        *CUnifiedNetwork::getNetBase(uint16 sid, TSockId &host, uint8 nid)
01312 {
01313         nlassertex(_Initialised == true, ("Try to CUnifiedNetwork::getNetBase() whereas it is not initialised yet"));
01314 
01315         if (ThreadCreator != NLMISC::getThreadId()) nlwarning ("HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u", ThreadCreator, NLMISC::getThreadId());
01316 
01317         if (sid >= _IdCnx.size () || _IdCnx[sid].State != CUnifiedNetwork::CUnifiedConnection::Ready)
01318         {
01319                 nlwarning ("HNETL5: Can't get net base to the service '%hu' because not in _IdCnx", sid);
01320                 host = InvalidSockId;
01321                 return NULL;
01322         }
01323 
01324         uint8 connectionId = findConnectionId (sid, nid);
01325         if (connectionId == 0xff)       // failed
01326         {
01327                 nlwarning ("Can't getNetBase %hu because no connection available", sid);
01328                 host = InvalidSockId;
01329                 return NULL;
01330         }
01331 
01332         host = _IdCnx[sid].Connection[connectionId].HostId;
01333         return _IdCnx[sid].Connection[connectionId].CbNetBase;
01334 }
01335 
01336 TUnifiedMsgCallback CUnifiedNetwork::findCallback (const std::string &callbackName)
01337 {
01338         TMsgMappedCallback::iterator    itcb = _Callbacks.find(callbackName);
01339         if (itcb == _Callbacks.end())
01340                 return NULL;
01341         else
01342                 return (*itcb).second;
01343 }
01344 
01345 bool CUnifiedNetwork::isServiceLocal (const std::string &serviceName)
01346 {
01347         // it s me, of course we are local
01348         if (serviceName == _Name)
01349                 return true;
01350 
01351         pair<TNameMappedConnection::const_iterator,TNameMappedConnection::const_iterator>       range;
01352         range = _NamedCnx.equal_range(serviceName);
01353 
01354         bool found = false;
01355         if (range.first != _NamedCnx.end())
01356         {
01357                 uint16  sid = (*(range.first)).second;
01358                 return isServiceLocal (sid);
01359         }
01360 
01361         return false;
01362 }
01363 
01364 bool CUnifiedNetwork::isServiceLocal (uint16 sid)
01365 {
01366         // it s me, of course we are local
01367         if (sid == _SId)
01368                 return true;
01369 
01370         if (sid >= _IdCnx.size () || _IdCnx[sid].State != CUnifiedNetwork::CUnifiedConnection::Ready)
01371         {
01372                 return false;
01373         }
01374 
01375         vector<CInetAddress> laddr = CInetAddress::localAddresses();
01376 
01377         for (uint i = 0; i < laddr.size(); i++)
01378         {
01379                 for (uint j = 0; j < _IdCnx[sid].ExtAddress.size(); j++)
01380                 {
01381                         if (_IdCnx[sid].ExtAddress[j].is127001 ())
01382                                 return true;
01383 
01384                         if (_IdCnx[sid].ExtAddress[j].internalIPAddress () == laddr[i].internalIPAddress ())
01385                                 return true;
01386                 }
01387         }
01388         return false;
01389 }
01390 
01391 //
01392 //
01393 //
01394 
01395 CUnifiedNetwork *CUnifiedNetwork::_Instance = NULL;
01396 
01397 CUnifiedNetwork *CUnifiedNetwork::getInstance ()
01398 {
01399         if (_Instance == NULL)
01400                 _Instance = new CUnifiedNetwork();
01401 
01402         return _Instance;
01403 }
01404 
01405 bool CUnifiedNetwork::isUsed ()
01406 {
01407         return (_Instance != NULL);
01408 }
01409 
01410 //
01411 //
01412 //
01413 
01414 CUnifiedNetwork::CUnifiedConnection     *CUnifiedNetwork::getUnifiedConnection (uint16 sid)
01415 {
01416         if (sid < _IdCnx.size () && _IdCnx[sid].State == CUnifiedConnection::Ready)
01417         {
01418                 if (sid != _IdCnx[sid].ServiceId)
01419                 {
01420                         AUTOCHECK_DISPLAY ("Sid index %hu is not the same that in the entry %hu", sid, _IdCnx[sid].ServiceId);
01421                         return NULL;
01422                 }
01423                 return &_IdCnx[sid];
01424         }
01425         else
01426         {
01427                 nlwarning ("Try to get a bad unified connection (sid %hu is not in the table)", sid);
01428                 return NULL;
01429         }
01430 }
01431 
01432 void    CUnifiedNetwork::autoCheck()
01433 {
01434         uint i, j;
01435 
01436         for (i = 0; i < _IdCnx.size (); i++)
01437         {
01438                 if (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::Ready)
01439                 {
01440                         _IdCnx[i].AutoCheck = 1;
01441                 }
01442                 else
01443                 {
01444                         _IdCnx[i].AutoCheck = 0;
01445                 }
01446         }
01447 
01448         TNameMappedConnection::iterator itn;
01449         for (itn = _NamedCnx.begin(); itn != _NamedCnx.end(); ++itn)
01450         {
01451                 if ((*itn).first != _IdCnx[(*itn).second].ServiceName) AUTOCHECK_DISPLAY ("HLNET5: problem with name syncro between _NameCnx and _IdCnx '%s' '%s' '%d'", (*itn).first.c_str(), _IdCnx[(*itn).second].ServiceName.c_str (), (*itn).second);
01452                 if (_IdCnx[(*itn).second].AutoCheck == 0)  AUTOCHECK_DISPLAY ("HLNET5: problem with name syncro between _NameCnx '%s' and _IdCnx '%s' '%d'", (*itn).first.c_str(), _IdCnx[(*itn).second].ServiceName.c_str (), (*itn).second);
01453                 if (_IdCnx[(*itn).second].AutoCheck > 1)  AUTOCHECK_DISPLAY ("HLNET5: problem with name syncro between _NameCnx and _IdCnx '%s' '%d' more than one entry in named with the same name", (*itn).first.c_str(), _IdCnx[(*itn).second].ServiceName.c_str (),(*itn).second);
01454                 _IdCnx[(*itn).second].AutoCheck++;
01455         }
01456 
01457         for (i = 0; i < _UsedConnection.size (); i++)
01458         {
01459                 if (_IdCnx[_UsedConnection[i]].State != CUnifiedNetwork::CUnifiedConnection::Ready) AUTOCHECK_DISPLAY ("HLNET5: problem with the _UsedConnection syncro sid %d is not used in _IdCnx", _UsedConnection[i]);
01460         }
01461         
01462         for (i = 0; i < _IdCnx.size (); i++)
01463         {
01464                 if (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::Ready)
01465                 {
01466                         for (j = 0; j < _UsedConnection.size (); j++)
01467                         {
01468                                 if (_UsedConnection[j] == i) break;
01469                         }
01470                         if (j == _UsedConnection.size ()) AUTOCHECK_DISPLAY ("HLNET5: problem with the _UsedConnection syncro sid %d is not in _UsedConnection", i);
01471                 }
01472         }
01473         
01474         for (i = 0; i < _IdCnx.size (); i++)
01475         {
01476                 if (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::NotUsed)
01477                 {
01478                         if (_IdCnx[i].ServiceName != "DEAD") AUTOCHECK_DISPLAY ("HLNET5: sid %d name should be DEAD and is '%s'", i, _IdCnx[i].ServiceName.c_str ());
01479                         if (_IdCnx[i].ServiceId != 0xDEAD) AUTOCHECK_DISPLAY ("HLNET5: sid %d sid should be 0xDEAD and is 0x%X", i, _IdCnx[i].ServiceId);
01480                         if (!_IdCnx[i].Connection.empty ()) AUTOCHECK_DISPLAY ("HLNET5: sid %d connection size should be 0 and is %d", i, _IdCnx[i].Connection.size ());
01481                         if (!_IdCnx[i].ExtAddress.empty ()) AUTOCHECK_DISPLAY ("HLNET5: sid %d ext addr size should be 0 and is %d", i, _IdCnx[i].ExtAddress.size ());
01482                         if (_IdCnx[i].AutoCheck != 0) AUTOCHECK_DISPLAY ("HLNET5: sid %d prob with syncro with _NamedCnx", i);
01483                 }
01484                 else if (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::Ready)
01485                 {
01486                         if (_IdCnx[i].ServiceId != i) AUTOCHECK_DISPLAY ("HNETL5: Bad syncro sid index sid entry for %d %d", i, _IdCnx[i].ServiceId);
01487 
01488                         if (_IdCnx[i].ServiceName == "DEAD") AUTOCHECK_DISPLAY ("HLNET5: sid %d name should not be DEAD and is '%s'", i, _IdCnx[i].ServiceName.c_str ());
01489                         if (_IdCnx[i].ServiceId == 0xDEAD) AUTOCHECK_DISPLAY ("HLNET5: sid %d sid should not be 0xDEAD and is 0x%X", i, _IdCnx[i].ServiceId);
01490                         if (!_IdCnx[i].ExtAddress.empty () && _IdCnx[i].Connection.size () > _IdCnx[i].ExtAddress.size()) AUTOCHECK_DISPLAY ("HLNET5: sid %d ext addr size should not be 0 and is %d", i, _IdCnx[i].ExtAddress.size ());
01491 
01492                         if (_IdCnx[i].AutoRetry == true && _IdCnx[i].Connection.size () > 1) AUTOCHECK_DISPLAY ("HLNET5: sid %d auto retry with more than one connection %d", i, _IdCnx[i].Connection.size ());
01493                         if (_IdCnx[i].AutoRetry == true && _IdCnx[i].IsExternal == false) AUTOCHECK_DISPLAY ("HLNET5: sid %d auto retry with internal connection", i);
01494                         if (_IdCnx[i].AutoRetry == true && _IdCnx[i].Connection[0].valid() == false) AUTOCHECK_DISPLAY ("HLNET5: sid %d auto retry with invalid connection", i);
01495 
01496                         for (j = 0; j < _IdCnx[i].Connection.size (); j++)
01497                         {
01498                                 if (_IdCnx[i].Connection[j].valid() && !_IdCnx[i].Connection[j].IsServerConnection && _IdCnx[i].Connection[j].CbNetBase->connected () && _IdCnx[i].Connection[j].getAppId() != i) AUTOCHECK_DISPLAY ("HLNET5: sid %d bad appid %"NL_I64"X", i, _IdCnx[i].Connection[j].getAppId());
01499                         }
01500 
01501                         for (j = 0; j < _IdCnx[i].NetworkConnectionAssociations.size (); j++)
01502                         {
01503                                 if (_IdCnx[i].NetworkConnectionAssociations[j] != 0)
01504                                 {
01505                                         if (_NetworkAssociations[j] != _IdCnx[i].ExtAddress[_IdCnx[i].NetworkConnectionAssociations[j]].internalNetAddress ()) AUTOCHECK_DISPLAY ("HLNET5: sid %d nid %d have address 0x%08x and is not the good connection net 0x%08x", i, j, _NetworkAssociations[j], _IdCnx[i].ExtAddress[_IdCnx[i].NetworkConnectionAssociations[j]].internalNetAddress ());
01506                                 }
01507                         }
01508                 }
01509         }
01510 }
01511 
01512 
01513 void CUnifiedNetwork::displayInternalTables (NLMISC::CLog *log)
01514 {
01515         uint i, j;
01516         log->displayNL ("%d Named Connections:", _NamedCnx.size ());
01517         for (TNameMappedConnection::iterator it = _NamedCnx.begin(); it != _NamedCnx.end (); it++)
01518         {
01519                 log->displayNL ("> '%s' -> %hu", (*it).first.c_str(), (*it).second);
01520         }
01521 
01522         uint nbused = 0;
01523         for (i = 0; i < _IdCnx.size (); i++)
01524         {
01525                 if(_IdCnx[i].State != CUnifiedNetwork::CUnifiedConnection::NotUsed)
01526                         nbused++;
01527         }
01528 
01529         log->displayNL ("%u/%u Unified Connections:", nbused, _IdCnx.size ());
01530         for (i = 0; i < _IdCnx.size (); i++)
01531         {
01532                 if(_IdCnx[i].State != CUnifiedNetwork::CUnifiedConnection::NotUsed)
01533                 {
01534                         log->displayNL ("> %s-%hu %s %s %s (%d extaddr %d cnx)", _IdCnx[i].ServiceName.c_str (), _IdCnx[i].ServiceId, _IdCnx[i].IsExternal?"ext":"int", _IdCnx[i].AutoRetry?"autoretry":"noautoretry", _IdCnx[i].SendId?"sendid":"nosendid", _IdCnx[i].ExtAddress.size (), _IdCnx[i].Connection.size ());
01535                         uint maxc = _IdCnx[i].Connection.size ();
01536                         if(_IdCnx[i].Connection.size () <= _IdCnx[i].ExtAddress.size ())
01537                                 maxc = _IdCnx[i].ExtAddress.size ();
01538 
01539                         for (j = 0; j < maxc; j++)
01540                         {
01541                                 string base;
01542                                 if(j < _IdCnx[i].ExtAddress.size ())
01543                                 {
01544                                         base += _IdCnx[i].ExtAddress[j].asString ();
01545                                 }
01546                                 else
01547                                 {
01548                                         base += "notvalid";
01549                                 }
01550 
01551                                 string ext;
01552                                 if(j < _IdCnx[i].Connection.size () && _IdCnx[i].Connection[j].valid())
01553                                 {
01554                                         if(_IdCnx[i].Connection[j].IsServerConnection)
01555                                         {
01556                                                 ext += "server ";
01557                                         }
01558                                         else
01559                                         {
01560                                                 ext += "client ";
01561                                         }
01562                                         ext += _IdCnx[i].Connection[j].CbNetBase->getSockId (_IdCnx[i].Connection[j].HostId)->asString ();
01563                                         ext += " appid:" + toString(_IdCnx[i].Connection[j].getAppId());
01564                                         if (_IdCnx[i].Connection[j].CbNetBase->connected ())
01565                                                 ext += " connected";
01566                                         else
01567                                                 ext += " notconnected";
01568                                 }
01569                                 else
01570                                 {
01571                                         ext += "notvalid";
01572                                 }
01573 
01574                                 log->displayNL ("     - %s %s", base.c_str (), ext.c_str ());
01575                         }
01576                         for (j = 0; j < _IdCnx[i].NetworkConnectionAssociations.size (); j++)
01577                         {
01578                                 log->displayNL ("     * nid %d -> cnxn %hu", j, (uint16)_IdCnx[i].NetworkConnectionAssociations[j]);
01579                         }
01580                 }
01581         }
01582 
01583         log->displayNL ("%u Used Unified Connections:", _UsedConnection.size());
01584         for (i = 0; i < _UsedConnection.size (); i++)
01585         {
01586                 log->displayNL ("> %hu", _UsedConnection[i]);
01587         }
01588 
01589         log->displayNL ("%u Network Associations:", _NetworkAssociations.size());
01590         for (i = 0; i < _NetworkAssociations.size (); i++)
01591         {
01592                 log->displayNL ("> 0x%08x -> '%s'", _NetworkAssociations[i], internalIPAddressToString (_NetworkAssociations[i]).c_str ());
01593         }
01594 }
01595 
01596 bool CUnifiedNetwork::haveNamedCnx (const std::string &name, uint16 sid)
01597 {
01598         CUnifiedNetwork::TNameMappedConnection::iterator                                                                                        it;
01599         pair<CUnifiedNetwork::TNameMappedConnection::iterator,CUnifiedNetwork::TNameMappedConnection::iterator> range;
01600         range = _NamedCnx.equal_range(name);
01601 
01602         if (range.first != range.second)
01603         {
01604                 for (it=range.first; it!=range.second && (*it).second!=sid; ++it)
01605                         ;
01606                 
01607                 return (it != range.second);
01608         }
01609         return false;
01610 }
01611 
01612 void CUnifiedNetwork::addNamedCnx (const std::string &name, uint16 sid)
01613 {
01614         // check if not already inserted
01615         CUnifiedNetwork::TNameMappedConnection::iterator                                                                                        it;
01616         pair<CUnifiedNetwork::TNameMappedConnection::iterator,CUnifiedNetwork::TNameMappedConnection::iterator> range;
01617         range = _NamedCnx.equal_range(name);
01618 
01619         if (range.first != range.second)
01620         {
01621                 for (it=range.first; it!=range.second && (*it).second!=sid; ++it)
01622                         ;
01623 
01624                 if (it != range.second)
01625                 {
01626                         AUTOCHECK_DISPLAY ("Try to add 2 times the same connection %s-%hu", name.c_str(), sid);
01627                         return;
01628                 }
01629         }
01630 
01631 
01632         // insert the name in the map to be able to send message with the name
01633         _NamedCnx.insert(make_pair(name, sid));
01634 
01635         allstuffs += "+name "+name+"-"+toString(sid)+"\n";
01636         test.displayNL ("+name %s-%hu", name.c_str (), sid);
01637 }
01638 
01639 void CUnifiedNetwork::removeNamedCnx (const std::string &name, uint16 sid)
01640 {
01641         // get all map nodes of that service name
01642         CUnifiedNetwork::TNameMappedConnection::iterator                                                                                        it;
01643         pair<CUnifiedNetwork::TNameMappedConnection::iterator,CUnifiedNetwork::TNameMappedConnection::iterator> range;
01644         range = _NamedCnx.equal_range(name);
01645 
01646         // assume not empty
01647         if (range.first == range.second)
01648         {
01649                 AUTOCHECK_DISPLAY ("The unified connection %s-%hu wasn't on the _NamedCnx", name.c_str(), sid);
01650                 return;
01651         }
01652 
01653         // select good service id
01654         for (it=range.first; it!=range.second && (*it).second!=sid; ++it)
01655                 ;
01656 
01657         // assume id exists
01658         if (it == range.second)
01659         {
01660                 AUTOCHECK_DISPLAY ("The unified connection %s-%hu wasn't on the _NamedCnx", name.c_str(), sid);
01661                 return;
01662         }
01663 
01664         // remove service for map
01665         _NamedCnx.erase(it);
01666 
01667         allstuffs += "-name "+name+"-"+toString(sid)+"\n";
01668         test.displayNL ("-name %s-%hu", name.c_str (), sid);
01669 }
01670 
01671 void CUnifiedNetwork::addNetworkAssociation (const string &networkName, uint8 nid)
01672 {
01673         if (nid >= _NetworkAssociations.size ())
01674                 _NetworkAssociations.resize (nid+1, 0xFF);
01675 
01676         _NetworkAssociations[nid] = stringToInternalIPAddress (networkName);
01677         nlinfo ("HNETL5: Associate network '%s' 0x%08x '%s' to nid %hu", networkName.c_str(), _NetworkAssociations[nid], internalIPAddressToString (_NetworkAssociations[nid]).c_str(), (uint16)nid);
01678 }
01679 
01680 
01681 
01682 //
01683 //
01684 //
01685 
01686 
01687 //
01688 // Commands
01689 //
01690 
01691 static bool createMessage (CMessage &msgout, const vector<string> &args, CLog &log)
01692 {
01693         for (uint i = 2; i < args.size (); i+=2)
01694         {
01695                 string type = args[i+0];
01696                 string value = args[i+1];
01697 
01698                          if (type == "s8")                      { sint8  v = atoi(value.c_str()); msgout.serial (v); }
01699                 else if (type == "s16")                 { sint16 v = atoi(value.c_str()); msgout.serial (v); }
01700                 else if (type == "s32")                 { sint32 v = atoi(value.c_str()); msgout.serial (v); }
01701                 else if (type == "s64")                 { sint64 v = atoi(value.c_str()); msgout.serial (v); }
01702                 else if (type == "u8")                  { uint8  v = atoi(value.c_str()); msgout.serial (v); }
01703                 else if (type == "u16")                 { uint16 v = atoi(value.c_str()); msgout.serial (v); }
01704                 else if (type == "u32")                 { uint32 v = atoi(value.c_str()); msgout.serial (v); }
01705                 else if (type == "u64")                 { uint64 v = atoi(value.c_str()); msgout.serial (v); }
01706                 else if (type == "f")                   { float  v = (float)atof(value.c_str()); msgout.serial (v); }
01707                 else if (type == "d")                   { double v = atof(value.c_str()); msgout.serial (v); }
01708                 else if (type == "b")                   { bool v = atoi(value.c_str()) == 1; msgout.serial (v); }
01709                 else if (type == "s")                   { msgout.serial (value); }
01710                 else { log.displayNL ("type '%s' is not a valid type", type.c_str()); return false; }
01711         }
01712         return true;
01713 }
01714 
01715 /*
01716  * Simulate a message that comes from the network.
01717  *
01718  * for the bool (b type), you must set the value to 1 or 0
01719  * for the string (s type), we don't manage space inside a string
01720  * for stl containers, you have first to put a u32 type that is the size of the container and after all elements
01721  * (ex: if you want to put a vector<uint16> that have 3 elements: u32 3 u16 10 u16 11 u16 12)
01722  *
01723  * ex: msgin 128 REGISTER u32 10 u32 541 u32 45
01724  * You'll receive a fake message REGISTER that seems to come from the service number 128 with 3 uint32.
01725  *
01726  */
01727 
01728 NLMISC_COMMAND(msgin, "Simulate an input message from another service (ex: msgin 128 REGISTER u32 10 b 1 f 1.5)", "<ServiceName>|<ServiceId> <MessageName> [<ParamType> <Param>]*")
01729 {
01730         if(args.size() < 2) return false;
01731         
01732         if (!CUnifiedNetwork::isUsed ())
01733         {
01734                 log.displayNL("Can't do that because the service doesn't use CUnifiedNetwork");
01735                 return false;
01736         }
01737 
01738         uint16 serviceId = atoi (args[0].c_str());
01739         string serviceName = args[0].c_str();
01740         string messageName = args[1].c_str();
01741         
01742         if (serviceId > 255)
01743         {
01744                 log.displayNL ("Service Id %d must be between [1;255]", serviceId);
01745                 return false;
01746         }
01747         
01748         if ((args.size()-2) % 2 != 0)
01749         {
01750                 log.displayNL ("The number of parameter must be a multiple of 2");
01751                 return false;
01752         }
01753 
01754         CMessage msg (messageName);
01755         msg.clear ();
01756 
01757         if (!createMessage (msg, args, log))
01758                 return false;
01759 
01760         msg.invert ();
01761 
01762         TUnifiedMsgCallback cb = CUnifiedNetwork::getInstance()->findCallback (messageName);
01763         
01764         if (cb == NULL)
01765         {
01766                 log.displayNL ("Callback for message '%s' is not found", messageName.c_str());
01767         }
01768         else
01769         {
01770                 cb (msg, serviceName, serviceId);
01771         }
01772         
01773                 
01774         return true;
01775 }
01776 
01777 /*
01778  * Create a message and send it to the specified service
01779  *
01780  * for the bool (b type), you must set the value to 1 or 0
01781  * for the string (s type), we don't manage space inside a string
01782  * for stl containers, you have first to put a u32 type that is the size of the container and after all elements
01783  * (ex: if you want to put a vector<uint16> that have 3 elements: u32 3 u16 10 u16 11 u16 12)
01784  *
01785  * ex: msgout 128 REGISTER u32 10 u32 541 u32 45
01786  * You'll send a real message REGISTER to the service number 128 with 3 uint32.
01787  *
01788  */
01789 
01790 NLMISC_COMMAND(msgout, "Send a message to a specified service (ex: msgout 128 REGISTER u32 10 b 1 f 1.5)", "<ServiceName>|<ServiceId> <MessageName> [<ParamType> <Param>]*")
01791 {
01792         if(args.size() < 2) return false;
01793 
01794         if (!CUnifiedNetwork::isUsed ())
01795         {
01796                 log.displayNL("Can't do that because the service doesn't use CUnifiedNetwork");
01797                 return false;
01798         }
01799 
01800         uint16 serviceId = atoi (args[0].c_str());
01801         string serviceName = args[0].c_str();
01802         string messageName = args[1].c_str();
01803         
01804         if (serviceId > 255)
01805         {
01806                 log.displayNL ("Service Id %d must be between [1;255]", serviceId);
01807                 return false;
01808         }
01809         
01810         if ((args.size()-2) % 2 != 0)
01811         {
01812                 log.displayNL ("The number of parameter must be a multiple of 2");
01813                 return false;
01814         }
01815 
01816         CMessage msg (messageName);
01817 
01818         if (!createMessage (msg, args, log))
01819                 return false;
01820 
01821         TSockId host = InvalidSockId;
01822         CCallbackNetBase *cnb = NULL;
01823 
01824         if (serviceId != 0)
01825                 cnb = CUnifiedNetwork::getInstance()->getNetBase ((uint8)serviceId, host);
01826         else
01827                 cnb = CUnifiedNetwork::getInstance()->getNetBase (serviceName, host);
01828 
01829         if (cnb == NULL)
01830         {
01831                 log.displayNL ("'%s' is a bad <ServiceId> or <ServiceName>", args[0].c_str());
01832                 return false;
01833         }
01834 
01835         cnb->send (msg, host);
01836         
01837         return true;
01838 }
01839 
01840 NLMISC_COMMAND(l5InternalTables, "Displays internal table of network layer5", "")
01841 {
01842         if(args.size() != 0) return false;
01843 
01844         if (!CUnifiedNetwork::isUsed ())
01845         {
01846                 log.displayNL("Can't display internal table because layer5 is not used");
01847                 return false;
01848         }
01849 
01850         CUnifiedNetwork::getInstance ()->displayInternalTables(&log);
01851 
01852         return true;
01853 }
01854 
01855 NLMISC_COMMAND(isServiceLocal, "Says if a service is local or not compare with this service", "<sid>|<service name>")
01856 {
01857         if(args.size() != 1) return false;
01858 
01859         if (!CUnifiedNetwork::isUsed ())
01860         {
01861                 log.displayNL("Can't do that because the service doesn't use CUnifiedNetwork");
01862                 return false;
01863         }
01864 
01865         uint16 sid = atoi (args[0].c_str ());
01866         if (sid > 0)
01867         {
01868                 log.displayNL ("Service %s-%hu and sid %s are %son the same computer", CUnifiedNetwork::getInstance ()->_Name.c_str(), (uint16)CUnifiedNetwork::getInstance ()->_SId, args[0].c_str(), CUnifiedNetwork::getInstance ()->isServiceLocal (sid)?"":"not ");
01869         }
01870         else
01871         {
01872                 log.displayNL ("Service %s-%hu and %s are %son the same computer", CUnifiedNetwork::getInstance ()->_Name.c_str(), (uint16)CUnifiedNetwork::getInstance ()->_SId, args[0].c_str(), CUnifiedNetwork::getInstance ()->isServiceLocal (args[0])?"":"not ");
01873         }
01874 
01875         return true;
01876 }
01877 
01878 } // NLNET