public ConnectionState(Edge e, StatusMessage sm, LinkMessage lm, bool discon) { Edge = e; PeerLinkMessage = lm; StatusMessage = sm; Disconnected = discon; }
/** * When we get a new link message from an edge, we must * check several conditions to see if we can proceed with * the Link protocol. * This function checks those conditions and returns true * if we can proceed. * If we cannot proceed, it gives an ErrorMessage to send * back to the other side. * @param cph The CphState * @param err ErrorMessage to return. Is null if there is no error * @return true if we can connect, if false, err != null */ protected bool CanConnect(CphState cph, out ErrorMessage err) { Address local_add = _node.Address; LinkMessage lm = cph.LM; err = null; if (lm.Realm != _node.Realm) { err = new ErrorMessage(ErrorMessage.ErrorCode.RealmMismatch, "We are not in the same realm"); } else if ((lm.Remote.Address != null) && !local_add.Equals(lm.Remote.Address)) { /* * They are trying to reach a specific node, but it's not * us */ err = new ErrorMessage(ErrorMessage.ErrorCode.TargetMismatch, String.Format("target is {0}, but reached {1}", lm.Remote.Address, local_add)); } else if (lm.Local.Address.Equals(local_add)) { //You are me!!! err = new ErrorMessage(ErrorMessage.ErrorCode.ConnectToSelf, "You are me: "); } else if (1 == _disconnecting) { err = new ErrorMessage(ErrorMessage.ErrorCode.Disconnecting, String.Format("I am disconnecting. local: {0}", local_add)); } return(err == null); }
/** * @return true if olm is equivalent to this */ public override bool Equals(object olm) { LinkMessage lm = olm as LinkMessage; if (lm != null) { bool same = true; same &= (lm.Attributes.Count == Attributes.Count); same &= lm.ConTypeString == ConTypeString; same &= lm.Token.Equals(Token); if (same) { //Make sure all the attributes match: foreach (string key in lm.Attributes.Keys) { same &= lm.Attributes[key] == Attributes[key]; } } same &= lm.Local.Equals(_local_ni); same &= lm.Remote.Equals(_remote_ni); return(same); } else { return(false); } }
/** * 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.Realm.Equals(_node.Realm)) { throw new LinkException("Realm mismatch: " + _node.Realm + " != " + lm.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); }
/** * Prefered constructor for a Connection */ public Connection(Edge e, Address a, string connectiontype, StatusMessage sm, LinkMessage peerlm) { Address = a; ConType = String.Intern(connectiontype); CreationTime = DateTime.UtcNow; MainType = StringToMainType(ConType); //Mutable state: var cs = new ConnectionState(e, sm, peerlm, false); _state = new Mutable<ConnectionState>(cs); }
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")), string.Empty, tmp_add.ToString()); RoundTripHT(l1); }
/** * 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>(); }
/** * 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>(); }
/** * @return true if olm is equivalent to this */ public override bool Equals(object olm) { LinkMessage lm = olm as LinkMessage; bool same = false; if (lm != null) { same = lm.ConTypeString.Equals(ConTypeString); same &= lm.Token.Equals(Token); same &= lm.Remote.Equals(Remote); same &= lm.Local.Equals(Local); same &= lm.Realm.Equals(Realm); } return(same); }
/** * Prefered constructor for a Connection */ public Connection(Edge e, Address a, string connectiontype, StatusMessage sm, LinkMessage peerlm) { if (null == a) { throw new System.ArgumentNullException( String.Format("Address cannot be null in Connection: Edge: {0} contype: {1}", e, connectiontype)); } Address = a; ConType = String.Intern(connectiontype); CreationTime = DateTime.UtcNow; MainType = StringToMainType(ConType); //Mutable state: var cs = new ConnectionState(e, sm, peerlm, false); _state = new Mutable <ConnectionState>(cs); }
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); }
/** return the old state, and new state */ public Pair <ConnectionState, ConnectionState> SetEdge(Edge e, LinkMessage lm) { var res = _state.Update(delegate(ConnectionState old_state) { if (old_state.Disconnected) { throw new Exception(String.Format("Connection: {0} is disconnected", this)); } var new_state = new ConnectionState(e, old_state.StatusMessage, lm, false); return(new_state); }); ProtocolLog.WriteIf(ProtocolLog.Connections, String.Format( "SetEdge called on {0}, old Edge: {1}", this, res.First.Edge)); var ev = StateChangeEvent; if (null != ev) { ev(this, res); } return(res); }
/** * 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 = _node.Rpc; 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); } }
/** * Prefered constructor for a Connection */ public Connection(Edge e, Address a, string connectiontype, StatusMessage sm, LinkMessage peerlm) { if( null == a ) { throw new System.ArgumentNullException( String.Format("Address cannot be null in Connection: Edge: {0} contype: {1}", e, connectiontype)); } Address = a; ConType = String.Intern(connectiontype); CreationTime = DateTime.UtcNow; MainType = StringToMainType(ConType); //Mutable state: var cs = new ConnectionState(e, sm, peerlm, false); _state = new Mutable<ConnectionState>(cs); }
/** return the old state, and new state */ public Pair<ConnectionState,ConnectionState> SetEdge(Edge e, LinkMessage lm) { var res = _state.Update(delegate(ConnectionState old_state) { if( old_state.Disconnected ) { throw new Exception(String.Format("Connection: {0} is disconnected",this)); } var new_state = new ConnectionState(e, old_state.StatusMessage, lm, false); return new_state; }); var ev = StateChangeEvent; if( null != ev ) { ev(this, res); } return res; }
/** * 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 = _node.Rpc; 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 ); } }
/** * 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); lm_resp = new LinkMessage(lm.ConTypeString, n_info, remote_info, _node.Realm, lm.Token); } else { 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 new link message from an edge, we must * check several conditions to see if we can proceed with * the Link protocol. * This function checks those conditions and returns true * if we can proceed. * If we cannot proceed, it gives an ErrorMessage to send * back to the other side. * @param cph The CphState * @param err ErrorMessage to return. Is null if there is no error * @return true if we can connect, if false, err != null */ protected bool CanConnect(CphState cph, out ErrorMessage err) { ConnectionTable tab = _node.ConnectionTable; Address local_add = _node.Address; LinkMessage lm = cph.LM; err = null; /* We lock the connection table so it doesn't change between * the call to Contains and the call to Lock */ if (lm.Attributes["realm"] != _node.Realm) { err = new ErrorMessage(ErrorMessage.ErrorCode.RealmMismatch, "We are not in the same realm"); } else if ((lm.Remote.Address != null) && !local_add.Equals(lm.Remote.Address)) { /* * They are trying to reach a specific node, but it's not * us */ err = new ErrorMessage(ErrorMessage.ErrorCode.TargetMismatch, String.Format("target is {0}, but reached {1}", lm.Remote.Address, local_add)); } else if (lm.Local.Address.Equals(local_add)) { //You are me!!! err = new ErrorMessage(ErrorMessage.ErrorCode.ConnectToSelf, "You are me: "); } else if (1 == _disconnecting) { err = new ErrorMessage(ErrorMessage.ErrorCode.Disconnecting, String.Format("I am disconnecting. local: {0}", local_add)); } else { /* * Now we go to the ConnectionTable and try to * get a lock on the address so we can go forward * with the linking */ try { if (ProtocolLog.LinkDebug.Enabled) { ProtocolLog.Write(ProtocolLog.LinkDebug, String.Format( "ConnectionPacketHandler - Trying to lock connection table: {0},{1}", lm.Local.Address, lm.ConTypeString)); } tab.Lock(lm.Local.Address, lm.ConTypeString, cph); if (ProtocolLog.LinkDebug.Enabled) { ProtocolLog.Write(ProtocolLog.LinkDebug, String.Format( "ConnectionPacketHandler - Successfully locked connection table: {0},{1}", lm.Local.Address, lm.ConTypeString)); } } catch (ConnectionExistsException) { //We already have a connection of this type to this address err = new ErrorMessage(ErrorMessage.ErrorCode.AlreadyConnected, String.Format("We are already connected: {0}", local_add)); } catch (CTLockException) { if (ProtocolLog.LinkDebug.Enabled) { ProtocolLog.Write(ProtocolLog.LinkDebug, String.Format( "ConnectionPacketHandler - Cannot lock connection table: {0},{1}", lm.Local.Address, lm.ConTypeString)); } //Lock can throw this type of exception err = new ErrorMessage(ErrorMessage.ErrorCode.InProgress, "Address: " + lm.Local.Address.ToString() + " is locked"); } } return(err == null); }
/** * 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 = _node.Rpc; 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()); }
/** * 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 = _node.Rpc; 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(); }
public void RoundTripHT(LinkMessage lm) { LinkMessage lm2 = new LinkMessage(lm.ToDictionary()); Assert.AreEqual(lm, lm2, "LinkMessage HT Roundtrip"); }
public CphState(Edge e, LinkMessage lm) { Edge = e; LM = lm; }
public void RoundTripHT(LinkMessage lm) { LinkMessage lm2 = new LinkMessage( lm.ToDictionary() ); Assert.AreEqual( lm, lm2, "LinkMessage HT Roundtrip" ); }
/** * Get a StatusMessage for this node */ public IDictionary GetStatus(IDictionary status_message, ISender edge) { //we just got s status request if (1 == _disconnecting) { throw new AdrException((int)ErrorMessage.ErrorCode.Disconnecting, "disconnecting"); } StatusMessage sm = new StatusMessage(status_message); Edge from = GetEdge(edge); if (ProtocolLog.LinkDebug.Enabled) { ProtocolLog.Write(ProtocolLog.LinkDebug, String.Format( "{0} -start- sys:link.GetStatus({1},{2})", _node.Address, sm, edge)); } CphState cphstate = null; if (from != null) { cphstate = _edge_to_cphstate[from] as CphState; } /** * StatusMessage objects are used to verify the completion * of the Link protocol. If we receive a StatusMessage request * after we send a LinkMessage response, we know the other * Node got our LinkMessage response, and the connection * is active */ StatusMessage response = null; ConnectionTable tab = _node.ConnectionTable; if (cphstate != null) { try { LinkMessage lm_to_add = cphstate.LM; //This is part of connection process: response = _node.GetStatus(sm.NeighborType, lm_to_add.Local.Address); Connection con = new Connection(from, lm_to_add.Local.Address, lm_to_add.ConTypeString, sm, lm_to_add); tab.Add(con); } finally { from.CloseEvent -= this.CloseHandler; CloseHandler(from, null); } } else { //This is just a "regular" status request //update our table: Address fadd = null; Connection c = tab.GetConnection(from); if (c != null) { fadd = c.Address; tab.UpdateStatus(c, sm); } response = _node.GetStatus(sm.NeighborType, fadd); } if (ProtocolLog.LinkDebug.Enabled) { ProtocolLog.Write(ProtocolLog.LinkDebug, String.Format( "{0} -end- sys:link.GetStatus()->{1}", _node.Address, response)); } return(response.ToDictionary()); }
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); }
/** * 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 ); }