/** * 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); }
/** * When an Edge closes, we must remove it from out * Hashtable. * @param edge the Edge that closed */ public void CloseHandler(object edge, EventArgs args) { CphState cphstate = null; lock (_sync) { cphstate = (CphState)_edge_to_cphstate[edge]; if (cphstate != null) { _edge_to_cphstate.Remove(edge); } } }
/** * When an Edge closes, we must remove it from out * Hashtable. * @param edge the Edge that closed */ public void CloseHandler(object edge, EventArgs args) { CphState cphstate = null; lock (_sync) { cphstate = (CphState)_edge_to_cphstate[edge]; if (cphstate != null) { _edge_to_cphstate.Remove(edge); } } if (cphstate != null) { ConnectionTable tab = _node.ConnectionTable; tab.Unlock(cphstate.LM.ConTypeString, cphstate); } }
/** * 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 = 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 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); }
/** * 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()); }
/** * 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); 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()); }