Esempio n. 1
0
    /**
     * Prefered constructor for a Connection
     */
    public Connection(Edge e, Address a,
		      string connectiontype,
		      StatusMessage sm, LinkMessage peerlm)
    {
      _e = e;
      _a = a;
      _ct = String.Intern(connectiontype);
      _stat = sm;
      _lm = peerlm;
      _creation_time = DateTime.UtcNow;
      MainType = StringToMainType(_ct);
    }
Esempio n. 2
0
    /**
     * Prefered constructor for a Connection
     */
    public Connection(Edge e, Address a,
		      string connectiontype,
		      StatusMessage sm, LinkMessage peerlm)
    {
      _e = e;
      _a = a;
      _ct = String.Intern(connectiontype);
      _stat = sm;
      _lm = peerlm;
      _creation_time = DateTime.UtcNow;
      MainType = StringToMainType(_ct);
      _as_dict = new WriteOnce<ListDictionary>();
      _sub_type = new WriteOnce<string>();
    }
 public CphState(Edge e, LinkMessage lm) {
   Edge = e;
   LM = lm;
 }
    /**
     * This starts a linking operation on the given edge
     */
    public IDictionary Start(IDictionary link_message, ISender edge) {
      if(ProtocolLog.LinkDebug.Enabled)
        ProtocolLog.Write(ProtocolLog.LinkDebug, String.Format(
          "{0} -start- sys:link.Start", _node.Address));

      Edge from = GetEdge(edge);
      LinkMessage lm = new LinkMessage(link_message);
      if(ProtocolLog.LinkDebug.Enabled)
        ProtocolLog.Write(ProtocolLog.LinkDebug, String.Format(
          "{0} -args- sys:link.Start({1},{2})", _node.Address,lm,from));

      CphState cph = new CphState(from,lm);
      lock( _sync ) {
        if( !_edge_to_cphstate.ContainsKey( from ) ) {
          _edge_to_cphstate[from] = cph;
        }
        else {
          throw new AdrException((int)ErrorMessage.ErrorCode.InProgress,
                                 "Already have a link in progress on this edge");
        }
      }
      ErrorMessage err = null;
      if( CanConnect(cph, out err) ) {
        try {
          //If the CloseEvent was already called, this throws an exception
          from.CloseEvent += this.CloseHandler;
        }
        catch {
          CloseHandler(from, null);
          throw new AdrException((int)ErrorMessage.ErrorCode.EdgeClosed,
                                      "Edge Closed after receiving message");
        }
      }
      else {
        lock( _sync ) {
          _edge_to_cphstate.Remove(from);
        }
      }
      //Now we prepare our response
      LinkMessage lm_resp = null;
      if( err == null ) {
        //We send a response:
        NodeInfo n_info = NodeInfo.CreateInstance( _node.Address, from.LocalTA );
        NodeInfo remote_info = NodeInfo.CreateInstance( null, from.RemoteTA );
        System.Collections.Specialized.StringDictionary attrs =
                new System.Collections.Specialized.StringDictionary();
        attrs["type"] = String.Intern( lm.ConTypeString );
        attrs["realm"] = String.Intern( _node.Realm );
        lm_resp = new LinkMessage( attrs, n_info, remote_info , lm.Token);
      }
      else {
        if( err.Ec == ErrorMessage.ErrorCode.AlreadyConnected ) {
          /**
           * When we send the ErrorCode.AlreadyConnected,
           * we could have a stale connection, lets try pinging
           * the other node, if they are there, but have lost
           * the Edge, this may trigger the edge to close, causing
           * us to remove the Connection.
           * @todo consider putting this address on a "fast track"
           * to removal if we don't hear from it soon
           */
          ConnectionTable tab = _node.ConnectionTable;
          Connection c = tab.GetConnection( lm.ConnectionType,
                                             lm.Local.Address );
          if( c != null ) {
            RpcManager rpc = RpcManager.GetInstance(_node);
            rpc.Invoke(c.Edge, null, "sys:link.Ping", String.Empty);
          }
        }
      }
      if( err != null ) {
        throw new AdrException((int)err.Ec, err.Message);
      }
      if(ProtocolLog.LinkDebug.Enabled)
        ProtocolLog.Write(ProtocolLog.LinkDebug, String.Format(
          "{0} -end- sys:link.Start()->{1}", _node.Address,lm_resp));
      return lm_resp.ToDictionary();
    }
    /**
     * When we get a response to the sys:link method, this handled
     * is called
     */
    protected void LinkCloseHandler(object q, EventArgs args) {
      try {
        Channel resq = (Channel)q;
        //If the Channel is empty this will throw an exception:
        RpcResult res = (RpcResult)resq.Dequeue();
        /* Here's the LinkMessage response */
        LinkMessage lm = new LinkMessage( (IDictionary)res.Result );
        /**
         * This will set our LinkMessageReply variable.  It can
         * only be set once, so all future sets will fail.  It
         * will also make sure we have the lock on the target.
         * If we don't, that will throw an exception
         */
        SetAndCheckLinkReply(lm);
        //If we got here, we have our response and the Lock on _target_address
        StatusMessage sm = _node.GetStatus(_contype, lm.Local.Address);
        /* Make the call */
        Channel results = new Channel();
        results.CloseAfterEnqueue();
        results.CloseEvent += this.StatusCloseHandler;
        RpcManager rpc = RpcManager.GetInstance(_node);
	if (ProtocolLog.LinkDebug.Enabled) {
	      ProtocolLog.Write(ProtocolLog.LinkDebug, 
                String.Format(
                  "LPS target: {0} Invoking GetStatus() over edge: {1}",
                  _linker.Target, _e));
	}
        /*
         * This could throw an exception if the Edge is closed
         */
        rpc.Invoke(_e, results, "sys:link.GetStatus", sm.ToDictionary() );
      }
      catch(AdrException x) {
        /*
         * This happens when the RPC call has some kind of issue,
         * first we check for common error conditions:
         */
        _x.Value = x;
        Finish( GetResultForErrorCode(x.Code) );
      }
      catch(ConnectionExistsException x) {
        /* We already have a connection */
        _x.Value = x;
        Finish( Result.ProtocolError );
      }
      catch(CTLockException x) {
        //This is thrown when ConnectionTable cannot lock.  Lets try again:
        _x.Value = x;
        Finish( Result.RetryThisTA );
      }
      catch(LinkException x) {
        _x.Value = x;
        if( x.IsCritical ) { Finish( Result.MoveToNextTA ); }
        else { Finish( Result.RetryThisTA ); }
      }
      catch(InvalidOperationException) {
        //The queue never got anything
        Finish(Result.MoveToNextTA);
      }
      catch(EdgeException) {
        //The Edge is goofy, let's move on:
        Finish(Result.MoveToNextTA);
      }
      catch(Exception x) {
        //The protocol was not followed correctly by the other node, fail
        _x.Value = x;
        Finish( Result.RetryThisTA );
      } 
    }
 /**
  * Checks that everything matches up and the protocol
  * can continue, throws and exception if anything is
  * not okay
  */
 protected void SetAndCheckLinkReply(LinkMessage lm) {
   /* Check that the everything matches up 
    * Make sure the link message is Kosher.
    * This are critical errors.  This Link fails if these occur
    */
   if( lm.Local == null) {
     throw new LinkException("Bad response");
   }
   if( _node.Address.Equals( lm.Local.Address ) ) {
     //Somehow, we got a response from someone claiming to be us.
     throw new LinkException("Got a LinkMessage response from our address");
   }
   if( lm.ConTypeString != _contype ) {
     throw new LinkException("Link type mismatch: " + _contype + " != " + lm.ConTypeString );
   }
   if( !lm.Attributes["realm"].Equals( _node.Realm ) ) {
     throw new LinkException("Realm mismatch: " +
                             _node.Realm + " != " + lm.Attributes["realm"] );
   }
   if( lm.Local.Address == null ) {
     throw new LinkException("LinkMessage response has null Address");
   }
   if( (_linker.Target != null) && (!lm.Local.Address.Equals( _linker.Target )) ) {
     /*
      * This is super goofy.  Somehow we got a response from some node
      * we didn't mean to connect to.
      * This can happen in some cases with NATs since nodes behind NATs are
      * guessing which ports are correct, their guess may be incorrect, and
      * the NAT may send the packet to a different node.
      * In this case, we have a critical error, this TA is not correct, we
      * must move on to the next TA.
      */
     throw new LinkException(String.Format("Target mismatch: {0} != {1}",
                                           _linker.Target, lm.Local.Address), true, null );
   }
   /*
    * Okay, this lm looks good, we'll accept it.  This can only be done
    * once, and once it happens a future attempt will throw an exception
    */
   _lm_reply.Value = lm;
   
   ConnectionTable tab = _node.ConnectionTable;
   /*
    * This throws an exception if:
    * 0) we can't get the lock.
    * 1) we already have set _target_lock to something else
    */
   tab.Lock( lm.Local.Address, _contype, this );
 }
Esempio n. 7
0
    public void LMSerializationTest()
    {
      NodeInfo n1 = NodeInfo.CreateInstance(null, TransportAddressFactory.CreateInstance("brunet.tcp://127.0.0.1:45"));
      RandomNumberGenerator rng = new RNGCryptoServiceProvider();      
      AHAddress tmp_add = new AHAddress(rng);
      LinkMessage l1 = new LinkMessage(ConnectionType.Structured, n1,
				       NodeInfo.CreateInstance(new DirectionalAddress(DirectionalAddress.Direction.Left),
				       TransportAddressFactory.CreateInstance("brunet.tcp://127.0.0.1:837")), tmp_add.ToString() );
      RoundTripHT(l1);
      StringDictionary attrs = new StringDictionary();
      attrs["realm"] = "test_realm";
      attrs["type"] = "structured.near";
      LinkMessage l3 = new LinkMessage(attrs, n1, n1, tmp_add.ToString());
      RoundTripHT(l3);
    }
Esempio n. 8
0
 public void RoundTripHT(LinkMessage lm) {
   LinkMessage lm2 = new LinkMessage( lm.ToDictionary() );
   Assert.AreEqual( lm, lm2, "LinkMessage HT Roundtrip" );
 }