/** * Compute candidate scores for a shortcut connection. * @param start address computed by the SCO. * @param range nunber of candidate nodes. * @param cb callback function when candidate scores are available. * @param current current selection of the optimal in the provided range. */ public override void ComputeCandidates(Address start, int range, TargetSelectorDelegate cb, Address current) { Channel q = null; RequestState rs = null; lock(_sync) { #if VTS_DEBUG Console.Error.WriteLine("VTS local: {0}, start: {1}, range: {2}, count: {3}", _node.Address, start, range, _num_requests); #endif if (_num_requests == MAX_REQUESTS) { return; //do nothing and return; } _num_requests++; q = new Channel(); rs = new RequestState(start, range, cb, current); _channel_to_state[q] = rs; } //create a new request state ISender s = new ForwardingSender(_node, start, AHHeader.Options.Greedy, new DirectionalAddress(DirectionalAddress.Direction.Left), (short) range, AHHeader.Options.Path ); q.EnqueueEvent += new EventHandler(EnqueueHandler); q.CloseEvent += new EventHandler(CloseHandler); RpcManager rpc = RpcManager.GetInstance(_node); rpc.Invoke(s, q, "ncserver.EchoVivaldiState", new object[]{}); }
public void Test() { RandomNumberGenerator rng = new RNGCryptoServiceProvider(); AHAddress tmp_add = new AHAddress(rng); Node n = new StructuredNode(tmp_add, "unittest"); AHSender ah = new AHSender(n, AddressParser.Parse("brunet:node:JOJZG7VO6RFOEZJ6CJJ2WOIJWTXRVRP4")); ForwardingSender fs = new ForwardingSender(n, AddressParser.Parse("brunet:node:JOJZG7VO6RFOEZJ6CJJ2WOIJWTXRVRP4"), AddressParser.Parse("brunet:node:5FMQW3KKJWOOGVDO6QAQP65AWVZQ4VUQ")); string uri = "sender:ah?dest=JOJZG7VO6RFOEZJ6CJJ2WOIJWTXRVRP4&mode=exact"; ISender s = SenderFactory.CreateInstance(n, uri); Assert.IsTrue(s is AHSender); Assert.AreEqual(uri, s.ToUri()); uri = "sender:ah?dest=JOJZG7VO6RFOEZJ6CJJ2WOIJWTXRVRP4&mode=greedy"; //Create the above programatically IDictionary<string, string> param_args = new Dictionary<string,string>(); param_args["dest"] = "JOJZG7VO6RFOEZJ6CJJ2WOIJWTXRVRP4"; param_args["mode"] = "greedy"; string uri0 = SenderFactory.EncodeUri("ah", param_args); Assert.AreEqual(uri, uri0, "EncodeUri works"); //Check decode: string scheme; param_args = SenderFactory.DecodeUri(uri, out scheme); Assert.AreEqual(scheme, "ah", "Scheme decoded"); Assert.AreEqual(param_args.Count, 2, "2 parameters in uri"); Assert.AreEqual(param_args["dest"], "JOJZG7VO6RFOEZJ6CJJ2WOIJWTXRVRP4", "Extracted address"); Assert.AreEqual(param_args["mode"], "greedy", "got mode"); s = SenderFactory.CreateInstance(n, uri); Assert.IsTrue(s is AHSender); Assert.AreEqual(uri, s.ToUri()); string furi = "sender:fw?relay=JOJZG7VO6RFOEZJ6CJJ2WOIJWTXRVRP4&init_mode=greedy&dest=5FMQW3KKJWOOGVDO6QAQP65AWVZQ4VUQ&ttl=3&mode=path"; s = SenderFactory.CreateInstance(n, furi); Assert.IsTrue(s is ForwardingSender); Assert.AreEqual(furi, s.ToUri()); }
/** * This handles the packet forwarding protocol */ public void HandleData(MemBlock b, ISender ret_path, object state) { /* * Check it */ AHSender ahs = ret_path as AHSender; if( ahs != null ) { //This was an AHSender: /* * This goes A -> B -> C */ if( b[0] == 0 ) { int offset = 1; //This is the first leg, going from A->B Address add_c = AddressParser.Parse(b.Slice(offset, Address.MemSize)); offset += Address.MemSize; //Since ahs a sender to return, we would be the source: Address add_a = ahs.Destination; short ttl = NumberSerializer.ReadShort(b, offset);//2 bytes offset += 2; ushort options = (ushort) NumberSerializer.ReadShort(b, offset);//2 bytes offset += 2; MemBlock payload = b.Slice(offset); MemBlock f_header = MemBlock.Reference( new byte[]{1} ); /* * switch the packet from [A B f0 C] to [B C f 1 A] */ ICopyable new_payload = new CopyList(PType.Protocol.Forwarding, f_header, add_a, payload); /* * ttl and options are present in the forwarding header. */ AHSender next = new AHSender(_n, ahs.ReceivedFrom, add_c, ttl, options); next.Send(new_payload); } else if ( b[0] == 1 ) { /* * This is the second leg: B->C * Make a Forwarding Sender, and unwrap the inside packet */ Address add_a = AddressParser.Parse(b.Slice(1, Address.MemSize)); Address add_b = ahs.Destination; MemBlock rest_of_payload = b.Slice(1 + Address.MemSize); //Here's the return path: ISender new_ret_path = new ForwardingSender(_n, add_b, add_a); _n.HandleData(rest_of_payload, new_ret_path, this); } } else { //This is not (currently) supported. Console.Error.WriteLine("Got a forwarding request from: {0}", ret_path); } }
/** * @param structs the ConnectionList to work with * @param target_to_for a mapping of Address -> Address, if we want to * connect to the key, the value should be the forwarder * @param neighs an IEnumerable of NodeInfo objects. */ protected void ConnectToNearer(ConnectionList structs, IDictionary target_to_for, IEnumerable neighs) { Address nltarget; Address nrtarget; CheckForNearerNeighbors(structs, neighs, out nltarget, out nrtarget); if( nrtarget != null ) { Address forwarder = (Address)target_to_for[nrtarget]; ISender send = new ForwardingSender(_node, forwarder, nrtarget); ConnectTo(send, nrtarget, STRUC_NEAR, 1); } if( nltarget != null && !nltarget.Equals(nrtarget) ) { Address forwarder = (Address)target_to_for[nltarget]; ISender send = new ForwardingSender(_node, forwarder, nltarget); ConnectTo(send, nltarget, STRUC_NEAR, 1); } }
/** * Similar to the above except the forwarder is the same for all targets * @param cl ConnectionList of structs * @param forwarder the Node to forward through * @param ni an IEnumerable of NodeInfo objects representing neighbors * forwarder */ protected void ConnectToNearer(ConnectionList cl, Address forwarder, IEnumerable ni) { Address nltarget; Address nrtarget; CheckForNearerNeighbors(cl, ni, out nltarget, out nrtarget); if( nrtarget != null ) { ISender send = new ForwardingSender(_node, forwarder, nrtarget); ConnectTo(send, nrtarget, STRUC_NEAR, 1); } if( nltarget != null && !nltarget.Equals(nrtarget) ) { ISender send = new ForwardingSender(_node, forwarder, nltarget); ConnectTo(send, nltarget, STRUC_NEAR, 1); } }
/** * This method is called when a new Connection is added * to the ConnectionTable */ protected void ConnectHandler(object contab, EventArgs eargs) { lock( _sync ) { _last_connection_time = DateTime.UtcNow; _current_retry_interval = _DEFAULT_RETRY_INTERVAL; _need_left = -1; _need_right = -1; } if( IsActive == false ) { return; } ConnectionEventArgs args = (ConnectionEventArgs)eargs; Connection new_con = args.Connection; ConnectionList structs = null; if( new_con.MainType == ConnectionType.Structured ) { structs = args.CList; } else { if( new_con.MainType == ConnectionType.Leaf ) { /* * We just got a leaf. Try to use it to get a shortcut.near * This leaf could be connecting a new part of the network * to us. We try to connect to ourselves to make sure * the network is connected: */ Address target = GetSelfTarget(); //This is a near neighbor connection ISender send = new ForwardingSender(_node, new_con.Address, target); //Try to connect to the two nearest to us: ConnectTo(send, target, STRUC_NEAR, 2); } structs = _node.ConnectionTable.GetConnections(ConnectionType.Structured); } ConnectToNearer(structs, new_con.Address, new_con.Status.Neighbors); }
///////////////// Methods ////////////////////// /** * Starts the Overlord if we are active * * This method is called by the CheckState method * IF we have not seen any connections in a while * AND we still need some connections * */ public override void Activate() { #if POB_DEBUG Console.Error.WriteLine("In Activate: {0}", _node.Address); #endif if( IsActive == false ) { return; } DateTime now = DateTime.UtcNow; lock( _sync ) { if( now - _last_retry_time < _current_retry_interval ) { //Not time yet... return; } _last_retry_time = now; //Double the length of time we wait (resets to default on connections) _current_retry_interval += _current_retry_interval; _current_retry_interval = (_MAX_RETRY_INTERVAL < _current_retry_interval) ? _MAX_RETRY_INTERVAL : _current_retry_interval; } ConnectionTable tab = _node.ConnectionTable; //If we are going to connect to someone, this is how we //know who to use Address target = null; string contype = String.Empty; ISender sender = null; int desired_ctms = 1; ConnectionList structs = tab.GetConnections(ConnectionType.Structured); if( structs.Count < 2 ) { ConnectionList leafs = tab.GetConnections(ConnectionType.Leaf); if( leafs.Count == 0 ) { /* * We first need to get a Leaf connection */ return; } //We don't have enough connections to guarantee a connected //graph. Use a leaf connection to get another connection Connection leaf = null; //Make sure the following loop can't go on forever int attempts = 2 * leafs.Count; do { leaf = leafs[ _rand.Next( leafs.Count ) ]; attempts--; } while( leafs.Count > 1 && structs.Contains( leaf.Address ) && attempts > 0 ); //Now we have a random leaf that is not a //structured neighbor to try to get a new neighbor with: if( leaf != null ) { target = GetSelfTarget(); /* * This is the case of trying to find the nodes nearest * to ourselves, use the Annealing routing to get connected * more quickly */ sender = new ForwardingSender(_node, leaf.Address, target); //We are trying to connect to the two nearest nodes in one //one attempt, so wait for two distinct responses: desired_ctms = 2; //This is a near neighbor connection contype = STRUC_NEAR; } } if( structs.Count > 0 && sender == null ) { /** * We need left or right neighbors we send * a ConnectToMessage in the directons we * need. */ if( NeedLeftNeighbor ) { #if POB_DEBUG Console.Error.WriteLine("NeedLeftNeighbor: {0}", _node.Address); #endif target = new DirectionalAddress(DirectionalAddress.Direction.Left); short ttl = (short)DESIRED_NEIGHBORS; sender = new AHSender(_node, target, ttl, AHHeader.Options.Last); contype = STRUC_NEAR; } else if( NeedRightNeighbor ) { #if POB_DEBUG Console.Error.WriteLine("NeedRightNeighbor: {0}", _node.Address); #endif target = new DirectionalAddress(DirectionalAddress.Direction.Right); short ttl = (short)DESIRED_NEIGHBORS; sender = new AHSender(_node, target, ttl, AHHeader.Options.Last); contype = STRUC_NEAR; } } if( sender != null ) { ConnectTo(sender, target, contype, desired_ctms); } }
/** * This method is called when a new Connection is added * to the ConnectionTable */ protected void ConnectHandler(object contab, EventArgs eargs) { lock( _sync ) { _last_connection_time = DateTime.UtcNow; _current_retry_interval = _DEFAULT_RETRY_INTERVAL; _need_left = -1; _need_right = -1; _need_short = -1; _need_bypass = -1; } if( IsActive == false ) { return; } ConnectionEventArgs args = (ConnectionEventArgs)eargs; Connection new_con = args.Connection; #if SEND_DIRECTIONAL_TO_NEAR bool connect_left = false; bool connect_right = false; #endif ConnectionList structs = null; if( new_con.MainType == ConnectionType.Leaf ) { /* * We just got a leaf. Try to use it to get a shortcut.near * This leaf could be connecting a new part of the network * to us. We try to connect to ourselves to make sure * the network is connected: */ Address target = GetSelfTarget(); //This is a near neighbor connection string contype = STRUC_NEAR; ISender send = new ForwardingSender(_node, new_con.Address, target); //Try to connect to the two nearest to us: ConnectTo(send, contype, 2); } else if( new_con.MainType == ConnectionType.Structured ) { #if SEND_DIRECTIONAL_TO_NEAR int left_pos = cl.LeftInclusiveCount(_node.Address, new_con.Address); int right_pos = cl.RightInclusiveCount(_node.Address, new_con.Address); if( left_pos < DESIRED_NEIGHBORS ) { /* * This is a new left neighbor. Always * connect to the right of a left neighbor, * this will make sure we are connected to * our local neighborhood. */ connect_right = true; if( left_pos < DESIRED_NEIGHBORS - 1) { /* * Don't connect to the left of our most * left neighbor. If this is not our * most left neighbor, make sure we are * connected to his left */ connect_left = true; } } if( right_pos < DESIRED_NEIGHBORS ) { /* * This is a new right neighbor. Always * connect to the left of a right neighbor, * this will make sure we are connected to * our local neighborhood. */ connect_left = true; if( right_pos < DESIRED_NEIGHBORS - 1) { /* * Don't connect to the right of our most * right neighbor. If this is not our * most right neighbor, make sure we are * connected to his right */ connect_right = true; } } if( left_pos >= DESIRED_NEIGHBORS && right_pos >= DESIRED_NEIGHBORS ) { //This looks like a shortcut } #endif structs = args.CList; }//Done handling the structured connection case /* * Now see if we need to connect to any of the neighbors of this guy */ if( structs == null ) { structs = _node.ConnectionTable.GetConnections(ConnectionType.Structured); } ConnectToNearer(structs, new_con.Address, new_con.Status.Neighbors); //We also send directional messages. In the future we may find this //to be unnecessary ///@todo evaluate the performance impact of this: #if SEND_DIRECTIONAL_TO_NEAR if( nrtarget == null || nltarget == null ) { /** * Once we find nodes for which we can't get any closer, we * make sure we are connected to the right and left of that node. * * When we connect to a neighbor's neighbor with directional addresses * we need TTL = 2. 1 to get to the neighbor, 2 to get to the neighbor's * neighbor. */ short nn_ttl = 2; if( connect_right ) { ConnectToOnEdge(new DirectionalAddress(DirectionalAddress.Direction.Right), new_con.Edge, nn_ttl, STRUC_NEAR); } if( connect_left ) { ConnectToOnEdge(new DirectionalAddress(DirectionalAddress.Direction.Left), new_con.Edge, nn_ttl, STRUC_NEAR); } } #endif }
/// <summary>Used to send data over the tunnel via forwarding senders /// using a randomly selected peer from our overlap list.</summary> public void HandleEdgeSend(Edge from, ICopyable data) { TunnelEdge te = from as TunnelEdge; Connection forwarder = te.NextForwarder; if(te.RemoteID == -1) { Address target = (te.RemoteTA as TunnelTransportAddress).Target; ISender sender = new ForwardingSender(_node, forwarder.Address, target); sender.Send(new CopyList(PType.Protocol.Tunneling, te.MId, data)); } else { try { forwarder.Edge.Send(new CopyList(te.Header, te.MId, data)); } catch { // We could be sending aon a closed edge... we could deal with this // better, but let's just let the system take its natural course. } } }
public void Test() { RandomNumberGenerator rng = new RNGCryptoServiceProvider(); AHAddress tmp_add = new AHAddress(rng); Node n = new StructuredNode(tmp_add, "unittest"); AHSender ah = new AHSender(n, AddressParser.Parse("brunet:node:JOJZG7VO6RFOEZJ6CJJ2WOIJWTXRVRP4")); ForwardingSender fs = new ForwardingSender(n, AddressParser.Parse("brunet:node:JOJZG7VO6RFOEZJ6CJJ2WOIJWTXRVRP4"), AddressParser.Parse("brunet:node:5FMQW3KKJWOOGVDO6QAQP65AWVZQ4VUQ")); string uri = "sender:ah?dest=brunet:node:JOJZG7VO6RFOEZJ6CJJ2WOIJWTXRVRP4&mode=exact"; ISender s = SenderFactory.CreateInstance(n, uri); Assert.IsTrue(s is AHSender); Assert.AreEqual(uri, s.ToUri()); uri = "sender:ah?dest=brunet:node:JOJZG7VO6RFOEZJ6CJJ2WOIJWTXRVRP4&mode=greedy"; s = SenderFactory.CreateInstance(n, uri); Assert.IsTrue(s is AHSender); Assert.AreEqual(uri, s.ToUri()); uri = "sender:fw?relay=brunet:node:JOJZG7VO6RFOEZJ6CJJ2WOIJWTXRVRP4&init_mode=greedy&dest=brunet:node:5FMQW3KKJWOOGVDO6QAQP65AWVZQ4VUQ&ttl=3&mode=path"; s = SenderFactory.CreateInstance(n, uri); Assert.IsTrue(s is ForwardingSender); Assert.AreEqual(uri, s.ToUri()); }