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()); }
public ForwardingSender(Node n, Address forwarder, Address destination) : this(n, forwarder, AHHeader.Options.Exact, destination, AHSender.DefaultTTLFor(n.NetworkSize), AHHeader.Options.Annealing) { }
/** * Here we handle routing AHPackets */ public void HandleData(MemBlock data, ISender ret_path, object st) { AHState state = _state; //Read the state, it can't change after the read var header = new AHHeader(data); var payload = data.Slice(header.Length); Connection next_con; //Check to see if we can use a Leaf connection: int dest_idx = state.Leafs.IndexOf(header.Destination); if( dest_idx >= 0 ) { next_con = state.Leafs[dest_idx]; } else { var alg = state.GetRoutingAlgo(header); Pair<Connection, bool> result = alg.NextConnection(ret_path as Edge, header); if( result.Second ) { //Send a response exactly back to the node that sent to us var resp_send = new AHSender(_n, ret_path, header.Source, AHSender.DefaultTTLFor(_n.NetworkSize), AHHeader.Options.Exact); _n.HandleData( payload, resp_send, this); } next_con = result.First; } //Send it on: if( next_con != null ) { //Now we do the sending: var new_packet = new CopyList(PType.Protocol.AH, header.IncrementHops(), payload); try { next_con.Edge.Send(new_packet); } catch(EdgeException) { //Just drop the packet... } } }
///////////////// 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 there is a Disconnection from * the ConnectionTable */ protected void DisconnectHandler(object connectiontable, EventArgs args) { ConnectionEventArgs ceargs = (ConnectionEventArgs)args; Connection c = ceargs.Connection; lock( _sync ) { _last_connection_time = DateTime.UtcNow; _need_left = -1; _need_right = -1; _current_retry_interval = _DEFAULT_RETRY_INTERVAL; } if( !IsActive ) { return; } if( c.MainType != ConnectionType.Structured ) { //Just activate and see what happens: Activate(); return; } ConnectionList cl = ceargs.CList; int right_pos = cl.RightInclusiveCount(_node.Address, c.Address); if( right_pos < DESIRED_NEIGHBORS ) { //We lost a close friend. Address target = new DirectionalAddress(DirectionalAddress.Direction.Right); short ttl = (short)DESIRED_NEIGHBORS; string contype = STRUC_NEAR; ISender send = new AHSender(_node, target, ttl, AHHeader.Options.Last); ConnectTo(send, target, contype, 1); } int left_pos = cl.LeftInclusiveCount(_node.Address, c.Address); if( left_pos < DESIRED_NEIGHBORS ) { //We lost a close friend. Address target = new DirectionalAddress(DirectionalAddress.Direction.Left); short ttl = (short)DESIRED_NEIGHBORS; string contype = STRUC_NEAR; ISender send = new AHSender(_node, target, ttl, AHHeader.Options.Last); ConnectTo(send, target, contype, 1); } }
///////////////// 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); } }
public void HandleData(AHHeader header, ICopyable payload, ISender ret_path, object st) { AHState state = _state; //Read the state, it can't change after the read Connection next_con; //Check to see if we can use a Leaf connection: int dest_idx = state.Leafs.IndexOf(header.Destination); if( dest_idx >= 0 ) { next_con = state.Leafs[dest_idx]; } else { var alg = state.GetRoutingAlgo(header); Pair<Connection, bool> result = alg.NextConnection(ret_path as Edge, header); if( result.Second ) { //Send a response exactly back to the node that sent to us var resp_send = new AHSender(_n, ret_path, header.Source, AHSender.DefaultTTLFor(_n.NetworkSize), AHHeader.Options.Exact, header.Hops); MemBlock data = payload as MemBlock; if(data == null) { // Try to get the shared BufferAllocator, useful when we don't know // how big the data is, which in general is just as expensive as // doing a CopyTo... BufferAllocator ba = Interlocked.Exchange<BufferAllocator>(ref _ba, null); if( ba != null ) { try { int length = payload.CopyTo(ba.Buffer, ba.Offset); data = MemBlock.Reference(ba.Buffer, ba.Offset, length); ba.AdvanceBuffer(length); } catch(System.Exception x) { throw new SendException(false, "could not write the packet, is it too big?", x); } finally { Interlocked.Exchange<BufferAllocator>(ref _ba, ba); } } else { data = MemBlock.Copy(payload); } } _n.HandleData( data, resp_send, this); } next_con = result.First; } //Send it on: if( next_con != null ) { //Now we do the sending: var new_packet = new CopyList(PType.Protocol.AH, header.IncrementHops(), payload); try { next_con.State.Edge.Send(new_packet); } catch(SendException) { //Just drop the packet... } } }
/** * 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); } }
/** * 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); } }
public ForwardingSender(Node n, Address forwarder, ushort init_option, Address destination, short ttl, ushort option) { _n = n; _dest = destination; _sender = new AHSender(n, forwarder, init_option); _f_ttl = ttl; _f_option = option; byte[] f_buffer = new byte[4]; NumberSerializer.WriteShort(ttl, f_buffer, 0); NumberSerializer.WriteUShort(option, f_buffer, 2); _header = new CopyList(PType.Protocol.Forwarding, MemBlock.Reference(new byte[]{0}), destination, MemBlock.Reference(f_buffer) ); }
public object[] proxy(string node, int ahOptions, int maxResultsToWait, string method, params object[] args) { Address target = AddressParser.Parse(node); AHSender s = new AHSender(_node, target, (ushort)ahOptions); return this.Proxy(s, maxResultsToWait, method, args); }
public void HandleData(AHHeader header, ICopyable payload, ISender ret_path, object st) { AHState state = _state; //Read the state, it can't change after the read Connection next_con; //Check to see if we can use a Leaf connection: int dest_idx = state.Leafs.IndexOf(header.Destination); if (dest_idx >= 0) { next_con = state.Leafs[dest_idx]; } else { var alg = state.GetRoutingAlgo(header); Pair <Connection, bool> result = alg.NextConnection(ret_path as Edge, header); if (result.Second) { //Send a response exactly back to the node that sent to us var resp_send = new AHSender(_n, ret_path, header.Source, AHSender.DefaultTTLFor(_n.NetworkSize), AHHeader.Options.Exact, header.Hops); MemBlock data = payload as MemBlock; if (data == null) { // Try to get the shared BufferAllocator, useful when we don't know // how big the data is, which in general is just as expensive as // doing a CopyTo... BufferAllocator ba = Interlocked.Exchange <BufferAllocator>(ref _ba, null); if (ba != null) { try { int length = payload.CopyTo(ba.Buffer, ba.Offset); data = MemBlock.Reference(ba.Buffer, ba.Offset, length); ba.AdvanceBuffer(length); } catch (System.Exception x) { throw new SendException(false, "could not write the packet, is it too big?", x); } finally { Interlocked.Exchange <BufferAllocator>(ref _ba, ba); } } else { data = MemBlock.Copy(payload); } } _n.HandleData(data, resp_send, this); } next_con = result.First; } //Send it on: if (next_con != null) { //Now we do the sending: var new_packet = new CopyList(PType.Protocol.AH, header.IncrementHops(), payload); try { next_con.State.Edge.Send(new_packet); } catch (SendException) { //Just drop the packet... } } }