Exemplo n.º 1
0
    /**
     * 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;
    }