/** * Allow if we are transfering to a LinkProtocolState or ConnectionPacketHandler * Note this method does not change anything, if the transfer is done, it * is done by the ConnectionTable while it holds its lock. */ public bool AllowLockTransfer(Address a, string contype, ILinkLocker l) { bool allow = false; bool hold_lock = (a.Equals( _target_lock ) && contype == _contype); if( false == hold_lock ) { //We don't even hold this lock! throw new Exception( String.Format("{2} asked to transfer a lock({0}) we don't hold: ({1})", a, _target_lock, this)); } if( l is Linker ) { //Never transfer to another linker: } else if ( l is ConnectionPacketHandler.CphState ) { /** * The ConnectionPacketHandler only locks when it * has actually received a packet. This is a "bird in the * hand" situation, however, if both sides in the double * link case transfer the lock, then we have accomplished * nothing. * * There is a specific case to worry about: the case of * a firewall, where only one node can contact the other. * In this case, it may be very difficult to connect if * we don't eventually transfer the lock to the * ConnectionPacketHandler. In the case of bi-directional * connectivity, we only transfer the lock if the * address we are locking is greater than our own (which * clearly cannot be true for both sides). * * To handle the firewall case, we keep count of how * many times we have been asked to transfer the lock. On * the third time we are asked, we assume we are in the firewall * case and we allow the transfer, this is just a hueristic. */ int reqs = Interlocked.Increment(ref _cph_transfer_requests); if ( (reqs >= 3 ) || ( a.CompareTo( LocalNode.Address ) > 0) ) { allow = true; } } else if( l is LinkProtocolState ) { LinkProtocolState lps = (LinkProtocolState)l; /** * Or Transfer the lock to a LinkProtocolState if: * 1) We created this LinkProtocolState * 2) The LinkProtocolState has received a packet */ if( (lps.Linker == this ) && ( lps.LinkMessageReply != null ) ) { allow = true; } } #if LINK_DEBUG if (ProtocolLog.LinkDebug.Enabled) { ProtocolLog.Write(ProtocolLog.LinkDebug, String.Format("{0}: Linker({1}) {2}: transfering lock on {3} to {4}", _local_n.Address, _lid, (_target_lock == null), a, l)); } #endif return allow; }