XrdClientConnMgr.cc

Go to the documentation of this file.
00001 //////////////////////////////////////////////////////////////////////////
00002 //                                                                      //
00003 // XrdClientConnMgr                                                     //
00004 // Author: Fabrizio Furano (INFN Padova, 2004)                          //
00005 // Adapted from TXNetFile (root.cern.ch) originally done by             //
00006 //  Alvise Dorigo, Fabrizio Furano                                      //
00007 //          INFN Padova, 2003                                           //
00008 //                                                                      //
00009 // The connection manager maps multiple logical connections on a single //
00010 // physical connection.                                                 //
00011 // There is one and only one logical connection per client              //
00012 // and one and only one physical connection per server:port.            //
00013 // Thus multiple objects withing a given application share              //
00014 // the same physical TCP channel to communicate with a server.          //
00015 // This reduces the time overhead for socket creation and reduces also  //
00016 // the server load due to handling many sockets.                        //
00017 //                                                                      //
00018 //////////////////////////////////////////////////////////////////////////
00019 
00020 //       $Id: XrdClientConnMgr.cc 30949 2009-11-02 16:37:58Z ganis $
00021 
00022 const char *XrdClientConnMgrCVSID = "$Id: XrdClientConnMgr.cc 30949 2009-11-02 16:37:58Z ganis $";
00023 
00024 #include "XrdClient/XrdClientConnMgr.hh"
00025 #include "XrdClient/XrdClientDebug.hh"
00026 #include "XrdClient/XrdClientMessage.hh"
00027 #include "XrdClient/XrdClientLogConnection.hh"
00028 #include "XrdClient/XrdClientThread.hh"
00029 #include "XrdClient/XrdClientEnv.hh"
00030 #include "XrdClient/XrdClientSid.hh"
00031 #ifdef WIN32
00032 #include "XrdSys/XrdWin32.hh"
00033 #endif
00034 
00035 #include <assert.h>
00036 
00037 #ifdef AIX
00038 #include <sys/sem.h>
00039 #else
00040 #include <semaphore.h>
00041 #endif
00042 
00043 // For user info
00044 #ifndef WIN32
00045 #include <sys/types.h>
00046 #include <pwd.h>
00047 #endif
00048 
00049 // Max number allowed of logical connections ( 2**15 - 1, short int)
00050 #define XRC_MAXVECTSIZE 32767
00051 
00052 //_____________________________________________________________________________
00053 void * GarbageCollectorThread(void *arg, XrdClientThread *thr)
00054 {
00055    // Function executed in the garbage collector thread
00056 
00057    // Mask all allowed signals
00058    if (thr->MaskSignal(0) != 0)
00059       Error("GarbageCollectorThread", "Warning: problems masking signals");
00060 
00061    XrdClientConnectionMgr *thisObj = (XrdClientConnectionMgr *)arg;
00062 
00063    thr->SetCancelDeferred();
00064    thr->SetCancelOn();
00065 
00066    while (1) {
00067       thr->CancelPoint();
00068 
00069       thisObj->GarbageCollect();
00070 
00071       thr->CancelPoint();
00072 
00073       sleep(30);
00074 
00075    }
00076 
00077    return 0;
00078 }
00079 
00080 //_____________________________________________________________________________
00081 int DisconnectElapsedPhyConn(const char *key,
00082                              XrdClientPhyConnection *p, void *voidcmgr)
00083 {
00084    // Function applied to the hash table to disconnect the unused elapsed
00085    // physical connections
00086 
00087    XrdClientConnectionMgr *cmgr = (XrdClientConnectionMgr *)voidcmgr;
00088    assert(cmgr != 0);
00089 
00090    if (p) {
00091       if ((p->GetLogConnCnt() <= 0) && 
00092            p->ExpiredTTL() && p->IsValid()) {
00093          p->Touch();
00094          p->Disconnect();
00095       }
00096       
00097       if (!p->IsValid()) {
00098 
00099         // Make sure that we kill the socket in the case of conns killed by the server
00100         p->Touch();
00101         p->Disconnect();
00102 
00103         // And then add the instance to the trashed list
00104         cmgr->fPhyTrash.Push_back(p);
00105 
00106         // And remove the current from here
00107         return -1;
00108       }
00109    }
00110    
00111    // Process next
00112    return 0;
00113 }
00114 
00115 
00116 
00117 //_____________________________________________________________________________
00118 int DumpPhyConn(const char *key,
00119                 XrdClientPhyConnection *p, void *voidcmgr)
00120 {
00121 
00122   if (!p) {
00123     Info(XrdClientDebug::kUSERDEBUG, "DumpPhyConn", "Phyconn entry, key=NULL");
00124     return 0;
00125   }
00126   
00127   Info(XrdClientDebug::kUSERDEBUG, "DumpPhyConn", "Phyconn entry, key='" <<
00128        (key ? key : "***def***") <<
00129        "', LogCnt=" << p->GetLogConnCnt() << (p->IsValid() ? " Valid" : " NotValid") )
00130 
00131   // Process next
00132   return 0;
00133 }
00134 
00135 //_____________________________________________________________________________
00136 int DestroyPhyConn(const char *key,
00137                           XrdClientPhyConnection *p, void *voidcmgr)
00138 {
00139   // Function applied to the hash table to destroy all the phyconns
00140 
00141   XrdClientConnectionMgr *cmgr = (XrdClientConnectionMgr *)voidcmgr;
00142   assert(cmgr != 0);
00143 
00144   if (p) {
00145     p->UnsolicitedMsgHandler = 0;
00146     delete(p);
00147   }
00148 
00149    // Process next, remove current item
00150    return -1;
00151 }
00152 
00153 
00154 //_____________________________________________________________________________
00155 XrdClientConnectionMgr::XrdClientConnectionMgr() : fSidManager(0),
00156                                                    fGarbageColl(0)
00157 {
00158    // XrdClientConnectionMgr constructor.
00159    // Creates a Connection Manager object.
00160    // Starts the garbage collector thread.
00161 
00162    fLastLogIdUsed = 0;
00163 
00164    fGarbageColl = new XrdClientThread(GarbageCollectorThread);
00165    
00166    if (!fGarbageColl)
00167       Error("ConnectionMgr",
00168             "Can't create garbage collector thread: out of system resources");
00169    
00170    fGarbageColl->Run(this);
00171 
00172 
00173    fSidManager = new XrdClientSid();
00174    if (!fSidManager) {
00175      Error("ConnectionMgr",
00176            "Can't create sid manager: out of system resources");
00177      abort();
00178    }
00179 
00180 }
00181 
00182 //_____________________________________________________________________________
00183 XrdClientConnectionMgr::~XrdClientConnectionMgr()
00184 {
00185    // Deletes mutex locks, stops garbage collector thread.
00186 
00187    int i=0;
00188 
00189    {
00190       XrdSysMutexHelper mtx(fMutex);
00191 
00192       for (i = 0; i < fLogVec.GetSize(); i++)
00193          if (fLogVec[i]) Disconnect(i, FALSE);
00194 
00195    }
00196 
00197    if (fGarbageColl) {
00198      void *ret;
00199       fGarbageColl->Cancel();
00200       fGarbageColl->Join(&ret);
00201       delete fGarbageColl;
00202    }
00203 
00204    GarbageCollect();
00205 
00206    fPhyHash.Apply(DestroyPhyConn, this);
00207    delete fSidManager;
00208 }
00209 
00210 //_____________________________________________________________________________
00211 void XrdClientConnectionMgr::GarbageCollect()
00212 {
00213    // Get rid of unused physical connections. 'Unused' means not used for a
00214    // TTL time from any logical one. The TTL depends on the kind of remote
00215    // server. For a load balancer the TTL is very high, while for a data server
00216    // is quite small.
00217 
00218    // Mutual exclusion on the vectors and other vars
00219    XrdSysMutexHelper mtx(fMutex);
00220 
00221    if (fPhyHash.Num() > 0) {
00222 
00223      if(DebugLevel() >= XrdClientDebug::kUSERDEBUG)
00224        fPhyHash.Apply(DumpPhyConn, this);
00225 
00226       // Cycle all the physical connections to disconnect the elapsed ones
00227       fPhyHash.Apply(DisconnectElapsedPhyConn, this);
00228 
00229    }
00230 
00231    // Cycle all the trashed physical connections to destroy the elapsed once more
00232    // after a disconnection. Doing this way, a phyconn in async mode has
00233    // all the time it needs to terminate its reader thread pool
00234    for (int i = fPhyTrash.GetSize()-1; i >= 0; i--) {
00235 
00236      DumpPhyConn("Trashed connection",
00237                  fPhyTrash[i], this);
00238 
00239      if ( !fPhyTrash[i] || 
00240           ((fPhyTrash[i]->GetLogConnCnt() <= 0) && (fPhyTrash[i]->ExpiredTTL())) ) {
00241 
00242         if (fPhyTrash[i] && (fPhyTrash[i]->GetReaderThreadsCnt() <= 0)) {
00243            delete fPhyTrash[i];
00244            
00245 
00246         }
00247 
00248 
00249        fPhyTrash.Erase(i);
00250      }
00251    }
00252 
00253 }
00254 
00255 //_____________________________________________________________________________
00256 int XrdClientConnectionMgr::Connect(XrdClientUrlInfo RemoteServ)
00257 {
00258    // Connects to the remote server:
00259    //  - Looks first for an existing physical connection already bound to
00260    //    User@RemoteAddress:TcpPort;
00261    //  - If needed, creates a TCP channel to User@RemoteAddress:TcpPort
00262    //   (this is a physical connection);
00263    //  - Creates a logical connection and binds it to the previous 
00264    //    created physical connection;
00265    //  - Returns the logical connection ID. Every client will use this
00266    //    ID to deal with the server.
00267 
00268    XrdClientLogConnection *logconn = 0;
00269    XrdClientPhyConnection *phyconn = 0;
00270    CndVarInfo *cnd = 0;
00271 
00272    int newid = -1;
00273    bool phyfound = FALSE;
00274 
00275    // First we get a new logical connection object
00276    Info(XrdClientDebug::kHIDEBUG,
00277         "Connect", "Creating a logical connection...");
00278 
00279    logconn = new XrdClientLogConnection(fSidManager);
00280    if (!logconn) {
00281       Error("Connect", "Object creation failed. Aborting.");
00282       abort();
00283    }
00284 
00285    // If empty, fill the user name with the default to avoid fake mismatches
00286    if (RemoteServ.User.length() <= 0) {
00287 #ifndef WIN32
00288       struct passwd *pw = getpwuid(getuid());
00289       RemoteServ.User = (pw) ? pw->pw_name : "";
00290 #else
00291       char  name[256];
00292       DWORD length = sizeof (name);
00293       ::GetUserName(name, &length);
00294       RemoteServ.User = name;
00295 #endif
00296    }
00297 
00298    // Keys
00299    XrdOucString key;
00300    XrdOucString key1(RemoteServ.User.c_str(), 256); key1 += '@';
00301    key1 += RemoteServ.Host; key1 += ':'; key1 += RemoteServ.Port;
00302    XrdOucString key2(RemoteServ.User.c_str(), 256); key2 += '@';
00303    key2 += RemoteServ.HostAddr; key2 += ':'; key2 += RemoteServ.Port;
00304 
00305    do {
00306 
00307      
00308        fMutex.Lock();
00309        cnd = 0;
00310 
00311        cnd = fConnectingCondVars.Find(key1.c_str());
00312        if (!cnd) cnd = fConnectingCondVars.Find(key2.c_str());
00313 
00314        // If there are no connection attempts in progress...
00315        if (!cnd) {
00316 
00317          // If we already have a physical connection to that host:port, 
00318          // then we use that
00319          if (fPhyHash.Num() > 0) {
00320            XrdClientPhyConnection *p = 0;
00321 
00322            // We must avoid the unfortunate pick of a disconnected phyconn
00323            GarbageCollect();
00324 
00325            if (((p = fPhyHash.Find(key1.c_str())) ||
00326                 (p = fPhyHash.Find(key2.c_str()))) && p->IsValid()) {
00327              // We link that physical connection to the new logical connection
00328              phyconn = p;
00329              phyconn->CountLogConn();
00330              phyconn->Touch();
00331              logconn->SetPhyConnection(phyconn);
00332 
00333              phyfound = TRUE;
00334            }
00335            else {
00336              // no connection attempts in progress and no already established connections
00337              // Mark this as an ongoing attempt
00338              // Now we have a pending conn attempt
00339              fConnectingCondVars.Rep(key1.c_str(), new CndVarInfo(), 0, Hash_keepdata);
00340            }
00341          }
00342 
00343          fMutex.UnLock();
00344        }
00345        else {
00346          // this is an attempt which must wait for the result of a previous one
00347          // In any case after the wait we loop and recheck
00348          cnd->cv.Lock();
00349          cnd->cnt++;
00350          fMutex.UnLock();
00351          cnd->cv.Wait();         
00352          cnd->cnt--;
00353          cnd->cv.UnLock();
00354        }
00355 
00356    } while (cnd); // here cnd means "if there is a condvar to wait on"
00357 
00358    // We are here if cnd == 0
00359   
00360    if (!phyfound) {
00361       
00362       Info(XrdClientDebug::kHIDEBUG,
00363            "Connect",
00364            "Physical connection not found. Creating a new one...");
00365 
00366       if (DebugLevel() >= XrdClientDebug::kHIDEBUG)
00367         fPhyHash.Apply(DumpPhyConn, this);
00368 
00369 
00370       // If not already present, then we must build a new physical connection, 
00371       // and try to connect it
00372       // While we are trying to connect, the mutex must be unlocked
00373       // Note that at this point logconn is a pure local instance, so it 
00374       // does not need to be protected by mutex
00375       if (!(phyconn = new XrdClientPhyConnection(this, fSidManager))) {
00376          Error("Connect", "Object creation failed. Aborting.");
00377          abort();
00378       }
00379       if ( phyconn && phyconn->Connect(RemoteServ) ) {
00380 
00381          phyconn->CountLogConn();
00382          logconn->SetPhyConnection(phyconn);
00383 
00384          if (DebugLevel() >= XrdClientDebug::kHIDEBUG)
00385             Info(XrdClientDebug::kHIDEBUG,
00386                  "Connect",
00387                  "New physical connection to server " <<
00388                  RemoteServ.Host << ":" << RemoteServ.Port <<
00389                  " succesfully created.");
00390 
00391       } else {
00392 
00393         // The connection attempt failed, so we signal all the threads waiting for a result
00394         {
00395           XrdSysMutexHelper mtx(fMutex);
00396           int cnt;
00397 
00398           key = key1;
00399           cnd = fConnectingCondVars.Find(key.c_str());
00400           if (!cnd) { key = key2; cnd = fConnectingCondVars.Find(key.c_str()); }
00401           if (cnd) {
00402             cnd->cv.Lock();
00403             cnd->cv.Broadcast();
00404             fConnectingCondVars.Del(key.c_str());
00405             cnt = cnd->cnt;
00406             cnd->cv.UnLock();
00407 
00408             if (!cnt) {
00409               Info(XrdClientDebug::kHIDEBUG, "Connect",
00410                    "Destroying connection condvar for " << key );
00411               delete cnd;
00412             }
00413           }
00414         }
00415          delete logconn;
00416         // And then add the instance to the trashed list
00417          phyconn->Touch();
00418          fPhyTrash.Push_back(phyconn);
00419          //delete phyconn;
00420          
00421          return -1;
00422       }
00423 
00424    }
00425 
00426 
00427    // Now, we are connected to the host desired.
00428    // The physical connection can be old or newly created
00429    {
00430       XrdSysMutexHelper mtx(fMutex);
00431       phyconn->WipeStreamid(logconn->Streamid());
00432 
00433       // Then, if needed, we push the physical connection into its vector
00434       if (!phyfound) {
00435          if (!phyconn)
00436             Error("Connect"," problems connecting to " << key1);
00437          fPhyHash.Rep(key1.c_str(), phyconn, 0, Hash_keepdata);
00438       }
00439 
00440       if (fLogVec.GetSize() < XRC_MAXVECTSIZE) {
00441             // Then we push the logical connection into its vector, up to a max size
00442             fLogVec.Push_back(logconn);
00443             // and the new position is the ID
00444             newid = fLogVec.GetSize()-1;
00445       }
00446       else {
00447          // The array is too big, get a free slot, if any
00448          newid = -1;
00449          for (int i = 0; i < fLogVec.GetSize(); i++) {
00450             int idx = (fLastLogIdUsed + i) % fLogVec.GetSize();
00451             if (!fLogVec[idx]) {
00452                fLogVec[idx] = logconn;
00453                newid = idx;
00454                fLastLogIdUsed = idx;
00455                break;
00456             }
00457          }
00458          if (newid == -1) {
00459             delete logconn;
00460             Error("Connect", "Critical error - Out of allocated resources:"
00461                   " max number allowed of logical connections reached ("<<XRC_MAXVECTSIZE<<")");
00462             return -1;
00463          }
00464       }
00465 
00466       // Now some debug log
00467       if (DebugLevel() >= XrdClientDebug::kHIDEBUG) {
00468 
00469          int logCnt = 0;
00470          for (int i=0; i < fLogVec.GetSize(); i++)
00471             if (fLogVec[i])
00472                logCnt++;
00473 
00474          Info(XrdClientDebug::kHIDEBUG, "Connect",
00475               "LogConn: size:" << fLogVec.GetSize() << " count: " << logCnt <<
00476               "PhyConn: size:" << fPhyHash.Num());
00477       }
00478    
00479 
00480 
00481       // The connection attempt went ok, so we signal all the threads waiting for a result, if we can still find the corresponding condvar
00482       int cnt;
00483       //      if (!phyfound) {
00484         key = key1;
00485         cnd = fConnectingCondVars.Find(key.c_str());
00486         if (!cnd) { key = key2; cnd = fConnectingCondVars.Find(key.c_str()); }
00487         if (cnd) {
00488           cnd->cv.Lock();
00489           cnd->cv.Broadcast();
00490           fConnectingCondVars.Del(key.c_str());
00491           cnt = cnd->cnt;
00492           cnd->cv.UnLock();
00493 
00494           if (!cnt) {
00495             Info(XrdClientDebug::kHIDEBUG, "Connect",
00496                  "Destroying connection condvar for " << key );
00497             delete cnd;
00498           }
00499         }
00500         //      }
00501 
00502    } // mutex
00503 
00504    return newid;
00505 }
00506 
00507 //_____________________________________________________________________________
00508 void XrdClientConnectionMgr::Disconnect(int LogConnectionID, 
00509                                  bool ForcePhysicalDisc)
00510 {
00511    // Deletes a logical connection.
00512    // Also deletes the related physical one if ForcePhysicalDisc=TRUE.
00513    if (LogConnectionID < 0) return;
00514 
00515    {
00516       XrdSysMutexHelper mtx(fMutex);
00517 
00518       if ((LogConnectionID < 0) ||
00519           (LogConnectionID >= fLogVec.GetSize()) || (!fLogVec[LogConnectionID])) {
00520          Error("Disconnect", "Destroying nonexistent logconn " << LogConnectionID);
00521          return;
00522       }
00523 
00524 
00525       if (ForcePhysicalDisc) {
00526          // We disconnect the phyconn
00527          // But it will be removed by the garbagecollector as soon as possible
00528          // Note that here we cannot destroy the phyconn, since there can be other 
00529          // logconns pointing to it the phyconn will be removed when there are no 
00530          // more logconns pointing to it
00531          fLogVec[LogConnectionID]->GetPhyConnection()->UnsolicitedMsgHandler = 0;
00532          fLogVec[LogConnectionID]->GetPhyConnection()->Disconnect();
00533          GarbageCollect();
00534       }
00535       else
00536          fLogVec[LogConnectionID]->GetPhyConnection()->WipeStreamid(fLogVec[LogConnectionID]->Streamid());
00537     
00538       fLogVec[LogConnectionID]->GetPhyConnection()->Touch();
00539       delete fLogVec[LogConnectionID];
00540       fLogVec[LogConnectionID] = 0;
00541 
00542       Info(XrdClientDebug::kHIDEBUG, "Disconnect",
00543            " LogConnID: " << LogConnectionID <<" destroyed");
00544    }
00545 
00546 }
00547 
00548 //_____________________________________________________________________________
00549 int XrdClientConnectionMgr::ReadRaw(int LogConnectionID, void *buffer, 
00550                                int BufferLength)
00551 {
00552    // Read BufferLength bytes from the logical connection LogConnectionID
00553 
00554    XrdClientLogConnection *logconn;
00555 
00556    logconn = GetConnection(LogConnectionID);
00557 
00558    if (logconn) {
00559       return logconn->ReadRaw(buffer, BufferLength);
00560    }
00561    else {
00562       Error("ReadRaw", "There's not a logical connection with id " <<
00563            LogConnectionID);
00564 
00565       return(TXSOCK_ERR);
00566    }
00567 }
00568 
00569 //_____________________________________________________________________________
00570 XrdClientMessage *XrdClientConnectionMgr::ReadMsg(int LogConnectionID)
00571 {
00572    XrdClientLogConnection *logconn;
00573    XrdClientMessage *mex;
00574 
00575    logconn = GetConnection(LogConnectionID);
00576 
00577    // Now we get the message from the queue, with the timeouts needed
00578    // Note that the physical connection know about streamids, NOT logconnids !!
00579    mex = logconn->GetPhyConnection()->ReadMessage(logconn->Streamid());
00580 
00581    // Return the message unmarshalled to ClientServerCmd
00582    return mex;
00583 }
00584 
00585 //_____________________________________________________________________________
00586 int XrdClientConnectionMgr::WriteRaw(int LogConnectionID, const void *buffer, 
00587                                      int BufferLength, int substreamid) {
00588    // Write BufferLength bytes into the logical connection LogConnectionID
00589 
00590    XrdClientLogConnection *logconn;
00591 
00592    logconn = GetConnection(LogConnectionID);
00593 
00594    if (logconn) {
00595        return logconn->WriteRaw(buffer, BufferLength, substreamid);
00596    }
00597    else {
00598       Error("WriteRaw", "There's not a logical connection with id " <<
00599             LogConnectionID);
00600 
00601       return(TXSOCK_ERR);
00602    }
00603 }
00604 
00605 //_____________________________________________________________________________
00606 XrdClientLogConnection *XrdClientConnectionMgr::GetConnection( int LogConnectionID)
00607 {
00608    // Return a logical connection object that has LogConnectionID as its ID.
00609    XrdSysMutexHelper mtx(fMutex);
00610  
00611    return (LogConnectionID > -1) ? fLogVec[LogConnectionID] : (XrdClientLogConnection *)0;
00612 }
00613 
00614 //____________________________________________________________________________
00615 XrdClientPhyConnection *XrdClientConnectionMgr::GetPhyConnection(XrdClientUrlInfo server)
00616 {
00617   // Gets pointer to the physical connection to 'server', if any.
00618   // Return 0 if none is found.
00619 
00620   XrdClientPhyConnection *p = 0;
00621 
00622   // If empty, fill the user name with the default to avoid fake mismatches
00623   if (server.User.length() <= 0) {
00624 #ifndef WIN32
00625     struct passwd *pw = getpwuid(getuid());
00626     server.User = (pw) ? pw->pw_name : "";
00627 #else
00628     char  name[256];
00629     DWORD length = sizeof (name);
00630     ::GetUserName(name, &length);
00631     server.User = name;
00632 #endif
00633   }
00634 
00635   // Keys
00636   XrdOucString key;
00637   XrdOucString key1(server.User.c_str(), 256); key1 += '@';
00638   key1 += server.Host; key1 += ':'; key1 += server.Port;
00639   XrdOucString key2(server.User.c_str(), 256); key2 += '@';
00640   key2 += server.HostAddr; key2 += ':'; key2 += server.Port;
00641 
00642   if (fPhyHash.Num() > 0) {
00643     if (((p = fPhyHash.Find(key1.c_str())) ||
00644          (p = fPhyHash.Find(key2.c_str()))) && !(p->IsValid())) {
00645       // We found an invalid connection: do not use it
00646       p = 0;
00647     }
00648   }
00649 
00650   // Done
00651   return p;
00652 }
00653 
00654 //_____________________________________________________________________________
00655 UnsolRespProcResult XrdClientConnectionMgr::ProcessUnsolicitedMsg(XrdClientUnsolMsgSender *sender,
00656                                              XrdClientMessage *unsolmsg)
00657 {
00658    // We are here if an unsolicited response comes from a physical connection
00659    // The response comes in the form of an TXMessage *, that must NOT be
00660    // destroyed after processing. It is destroyed by the first sender.
00661    // Remember that we are in a separate thread, since unsolicited responses
00662    // are asynchronous by nature.
00663 
00664    //Info(XrdClientDebug::kDUMPDEBUG, "ConnectionMgr",
00665    //    "Processing unsolicited response (ID:"<<unsolmsg->HeaderSID()<<")");
00666    UnsolRespProcResult res = kUNSOL_CONTINUE;
00667    // Local processing ....
00668 
00669    // Now we propagate the message to the interested objects.
00670    // In our architecture, the interested objects are the objects which
00671    // self-registered in the logical connections belonging to the Phyconn
00672    // which threw the event
00673    // So we throw the evt towards each logical connection
00674    {
00675       // Find an interested logid
00676       XrdSysMutexHelper mtx(fMutex);
00677       
00678       for (int i = 0; i < fLogVec.GetSize(); i++) {
00679       
00680          if ( fLogVec[i] && (fLogVec[i]->GetPhyConnection() == sender) ) {
00681             fMutex.UnLock();
00682             res = fLogVec[i]->ProcessUnsolicitedMsg(sender, unsolmsg);
00683             fMutex.Lock();
00684 
00685             if (res != kUNSOL_CONTINUE) break;
00686          }
00687       }
00688    }
00689    return res;
00690 }

Generated on Tue Jul 5 14:46:18 2011 for ROOT_528-00b_version by  doxygen 1.5.1