/** * @param p the AHPacket to route * @param from The edge the packet came from * @param deliverlocally set to true if the local node should Announce it * @return the number of edges the packet it Sent on. */ public int Route(Edge from, AHPacket p, out bool deliverlocally) { Edge next = null; deliverlocally = false; int sent = 0; /* We can only route if it is a DirectionalAddress and we have * structured connections */ try { DirectionalAddress dir_add = (DirectionalAddress) p.Destination; /* We need to do a few atomic operations on the ConnectionTable */ ConnectionList structs = _con_tab.GetConnections(ConnectionType.Structured); Connection next_con = null; if ( dir_add.Bearing == DirectionalAddress.Direction.Left ) { //Get the left structured neighbor of us: next_con = structs.GetLeftNeighborOf(_local); if( next_con.Edge == from ) { //skip the person it came from next_con = structs.GetLeftNeighborOf(next_con.Address); } } else if (dir_add.Bearing == DirectionalAddress.Direction.Right) { //Get the left structured neighbor of us: next_con = structs.GetRightNeighborOf(_local); if( next_con.Edge == from ) { //skip the person it came from next_con = structs.GetRightNeighborOf(next_con.Address); } } if (next_con != null ) { //Here is the edge to go to next next = next_con.Edge; } if( p.HasOption( AHPacket.AHOptions.Path ) ) { deliverlocally = true; } else if( p.HasOption( AHPacket.AHOptions.Last ) ) { if( next == null || p.Hops == p.Ttl ) { deliverlocally = true; } } if ( (next != null) && (p.Hops < p.Ttl) //Send only packets with some Ttl left && (next != from) ) { //Don't send it the way it came no matter what //Increment the hops : //If we send it, set sent to 1 next.Send( p.IncrementHops() ); sent = 1; } } catch(System.Exception) { //_log.Error("DirectionalRouter exception:", x); if( next != null && next.IsClosed ) { //The edge is closed but not yet removed from the ConnectionTable //remove it and try again _con_tab.Disconnect(next); return Route(from, p, out deliverlocally); } } return sent; }
/** * Route the packet p which came from edge e, and set * deliverlocally to true if this packet should be delivered * to the local node. * * The routing algorithm can be summarized: * <ol> * <li>If Hops <= 1, route closest to the dest, other than previous, else:</li> * <li>If the closest is closer than the previous, route to closest, else:</li> * <li>stop</li> * </ol> * * Local delivery is done anytime there is either no next hop, * or the next hop is further from the destination than we are. * * @return the number of edges we send the packet to */ public int Route(Edge prev_e, AHPacket p, out bool deliverlocally) { #if AHROUTER_DEBUG bool debug = false; if (p.PayloadType == AHPacket.Protocol.ReqRep) { Console.Error.WriteLine("{0}: We have a ReqRep packet to route at: {1}", _local, System.DateTime.Now); //ReqrepManager.DebugPacket(_local, p, prev_e); debug = true; } else if (p.PayloadType == AHPacket.Protocol.IP) { Console.Error.WriteLine("{0}: We have a IP to route at: {1}", _local, System.DateTime.Now); debug = true; } else if (p.PayloadType == AHPacket.Protocol.Forwarding) { Console.Error.WriteLine("{0}: We have a Forwarding to route at: {1}", _local, System.DateTime.Now); debug = true; } else if (p.PayloadType == AHPacket.Protocol.Tunneling) { Console.Error.WriteLine("{0}: We have a Tunnel to route at: {1}", _local, System.DateTime.Now); debug = true; } #endif Connection next_con = null; //the next connection to send the packet to deliverlocally = false; AHAddress dest = (AHAddress)p.Destination; /* * The following cases don't require us to consult the Connection table */ short hops = p.Hops; short ttl = p.Ttl; if( hops > ttl ) { //This should never have gotten here: Console.Error.WriteLine( "Bad Packet from: {0}, hops({1}) > ttl({2})", prev_e, hops, ttl); return 0; } else if ( _local.Equals(dest) ) { //This packet is for us! Woo hoo! //There is no option that does not mean deliver in this case deliverlocally = true; //We can stop routing now, no one is closer than us. #if AHROUTER_DEBUG if (debug) { Console.Error.WriteLine("Delloc: {0}\n from: {1}\n delloc: {2}", p,prev_e,deliverlocally); Console.Error.WriteLine("{0}: We are the destination, WOW!", _local); } #endif return 0; } else if( hops == ttl ) { //We are the last to route the packet. if( p.HasOption( AHPacket.AHOptions.Last ) ) { /* * No need to check any routing tables. We get it */ deliverlocally = true; #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("{0}: TTL expired. Still deliverlocally (option Last).", _local); #endif return 0; } else { //We only deliver it if we are the nearest. //We check this below. } } CacheKey k = new CacheKey(dest, prev_e, p.Options ); //We've already checked hops == ttl, so we can ignore them for now CachedRoute cr = null; lock( _sync ) { //This looks like a Hashtable, but it's a Cache, //and we can't read from it without locking it cr = (CachedRoute)_route_cache[ k ]; } if( cr != null ) { //Awesome, we already know the path to this node. //This cuts down on latency next_con = cr.Route; deliverlocally = cr.DeliverLocally; #if AHROUTER_DEBUG if (debug) { if (next_con != null) { Console.Error.WriteLine("{0}: We found a cached route. local delivery: {1}, next_con: {2}.", _local, deliverlocally, next_con.Address); } else { Console.Error.WriteLine("{0}: We found a cached route. local delivery: {1}, next_con = null.", _local, deliverlocally); } } #endif } else { /* * else we know hops < ttl, we can route: * We now need to check the ConnectionTable */ next_con = _tab.GetConnection(ConnectionType.Leaf, dest); if( next_con == null ) { ConnectionList structs = _tab.GetConnections(ConnectionType.Structured); /* * We do not have a leaf connection to use, now we must * find a Structured connection over which to route the packet */ #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("{0}: We do not have a leaf connection.", _local); #endif int dest_idx = structs.IndexOf(dest); if( dest_idx >= 0 ) { //We actually have a connection to this node: #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("{0}: We have a structured connection to destination.", _local); #endif next_con = structs[dest_idx]; } else if( structs.Count == 0 ) { //We don't have any structured connections. I guess we are the closest: deliverlocally = true; next_con = null; } else { //dest_idx is not in the table: #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("{0}: We do not have a structured connection to destination.", _local); #endif dest_idx = ~dest_idx; /* * Here are the right and left neighbors of the destination * left is increasing, right is decreasing. * Remember the ConnectionTable wraps around, so no need to worry * about the size of index */ int left_idx = dest_idx; Connection left_n = structs[left_idx]; #if AHROUTER_DEBUG if (debug && left_n != null) Console.Error.WriteLine("{0}: key left connection: {1}.", _local, left_n.Address); #endif int right_idx = dest_idx - 1; Connection right_n = structs[right_idx]; #if AHROUTER_DEBUG if (debug && right_n != null) Console.Error.WriteLine("{0}: key right connection: {1}.", _local, right_n.Address); #endif //We check the a couple of connections: BigInteger l_dist = dest.DistanceTo((AHAddress)left_n.Address).abs(); BigInteger r_dist = dest.DistanceTo((AHAddress)right_n.Address).abs(); Connection closest_con; Connection other_con; BigInteger closest_dist; BigInteger other_dist; if( l_dist < r_dist ) { closest_con = left_n; other_con = right_n; closest_dist = l_dist; other_dist = r_dist; #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("{0}: Going the left way (since it is closer).", _local); #endif } else { closest_con = right_n; other_con = left_n; closest_dist = r_dist; other_dist = l_dist; #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("{0}: Going the right way (since it is closer).", _local); #endif } /** * Here we consider the various routing modes */ if( p.HasOption( AHPacket.AHOptions.Greedy ) ) { #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("{0}: Greedy routing mode.", _local); #endif /* * We pass it ONLY IF we can get it closer than we are. */ BigInteger our_dist = dest.DistanceTo(_local).abs(); if( closest_dist < our_dist ) { if( closest_con.Edge != prev_e ) { #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("{0}: Greedy. Closest distance is lesser than our distance.", _local); #endif next_con = closest_con; } else { #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("Got wrong greedy packet from: {0}", prev_e); #endif //This should never happen, a buggy client must have given //us a packet they shouldn't have: Console.Error.WriteLine("Got wrong greedy packet from: {0}", prev_e); next_con = null; } deliverlocally = false; } else { //We keep it. #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("{0}: Closest distance not lesser than us. Lets keep it.", _local); #endif next_con = null; deliverlocally = true; } } else { #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("{0}: Annealing routing mode.", _local); #endif //All the other routing modes use the Annealing rule #if AHROUTER_DEBUG if (debug) { if (_our_left_n != null) { Console.Error.WriteLine("{0}: our left connection: {1}", _local, _our_left_n.Address); } else { Console.Error.WriteLine("{0}: our left connection: null"); } try { Console.Error.WriteLine("{0}: Testing == between: {1} and {2}, equality: {3}", _local, left_n.Address, _our_left_n.Address, (left_n == _our_left_n)); Console.Error.WriteLine("{0}: Operand 1, hashcode: {1}, tostring(): {2}", _local, left_n.GetHashCode(), left_n); Console.Error.WriteLine("{0}: Operand 2, hashcode: {1}, tostring(): {2}", _local, _our_left_n.GetHashCode(), _our_left_n); Console.Error.WriteLine("{0}: Hashcode equality: {1}", _local, (left_n.GetHashCode() == _our_left_n.GetHashCode())); } catch(System.Exception e) { Console.Error.WriteLine("{0}: excption in debugging code!", _local); } } #endif if( left_n == _our_left_n ) { #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("{0}: I am adjacent to the destination (matching neighbors)", _local); #endif /* * We share a common left neighbor, so we should deliver locally * This is the only case where we should deliver locally, * otherwise there is at least one node on either side of the * target, so one of them should probably get the packet. */ deliverlocally = true; #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("{0}: Local delivery for sure. Who else gets it.", _local); #endif //The next step should be the node on the "other side" if( _local.IsLeftOf( dest ) ) { next_con = right_n; #if AHROUTER_DEBUG if (debug) { if (next_con != null) { Console.Error.WriteLine("{0}: Adjacent, also give to the guy on right: {1}", _local, next_con.Address); } else { Console.Error.WriteLine("{0}: Adjacent, also give to the guy on right: null", _local); } } #endif } else { next_con = left_n; #if AHROUTER_DEBUG if (debug) { if (next_con != null) { Console.Error.WriteLine("{0}: Adjacent, also give to the guy on left: {1}", _local, next_con.Address); } else { Console.Error.WriteLine("{0}: Adjacent, also give to the guy on left: null", _local); } } #endif } if( prev_e == next_con.Edge ) { //Don't send it back the way it came #if AHROUTER_DEBUG if (debug) Console.Error.WriteLine("{0}: Adjacent, dont send it back", _local); #endif next_con = null; } } else if ( hops == 0 ) { /* * This is the case that we sent the packet, and we are not * a neighbor of the packet (the previous case) * So, the closest_con must be good since we are the source */ next_con = closest_con; } else if (hops <= _MAX_UPHILL_HOPS ) { /* * We will allow the packet to go uphill (get further from the source) * at first, but this has to stop in order to prevent loops * * This may help the network form in the massive join case, or under * heavy churn. @todo analyze approaches for improving stabilization * in massively disordered cases. */ if( closest_con.Edge != prev_e ) { //Awesome. This is an easy case... next_con = closest_con; } else { /* * Look at the two next closest and choose the minimum distance of * the three */ int sc_idx = -1; if( closest_con == right_n ) { //move one over sc_idx = right_idx - 1; } else { //Must be the left: sc_idx = left_idx + 1; } Connection second_closest = structs[sc_idx]; BigInteger second_dist = dest.DistanceTo( (AHAddress)second_closest.Address).abs(); if( second_dist < other_dist ) { other_con = second_closest; } if( other_con.Edge != prev_e ) { //If we only have one neighbor, //other and closest might be the same next_con = other_con; } else { //We just can't win... next_con = null; } } } else { /* * This is the case where we are not a neighbor of the destination * according to our table, and the packet has taken at least 2 hops. */ deliverlocally = false; if( ( closest_con.Edge == prev_e ) && ( other_con.Edge != prev_e ) ) { closest_dist = other_dist; closest_con = other_con; } Connection prev = _tab.GetConnection(prev_e); if( prev != null ) { BigInteger prev_dist = dest.DistanceTo( (AHAddress)prev.Address ).abs(); if( closest_dist >= prev_dist ) { //Don't send it if you can't get it closer than it was before next_con = null; } else { next_con = closest_con; } } else { //This is the case that we don't have a connection //on the Edge the packet came from, this shouldn't happen, //but it is not a disaster. next_con = closest_con; } }//End of non-neareast neighbor case }//End of Annealing case }//End of the case where we had to find a near route } else { //We can route directly to the destination. } /* * We update the route cache with the most recent Edge to send to * that destination. */ lock(_sync ) { _route_cache[k] = new CachedRoute(next_con, deliverlocally); } }//End of cache check //Here are the other modes: if( p.HasOption( AHPacket.AHOptions.Last ) ) { if( next_con == null ) { deliverlocally = true; } else { deliverlocally = false; } } else if( p.HasOption( AHPacket.AHOptions.Path ) ) { deliverlocally = true; } else if( p.HasOption( AHPacket.AHOptions.Exact ) ) { if( _local.Equals(dest) ) { deliverlocally = true; next_con = null; } else { deliverlocally = false; } } /* * Now we have next_con if we can send it somewhere closer. */ try { if( next_con != null && (hops < ttl) ) { //We can send it on next_con.Edge.Send( p.IncrementHops() ); #if AHROUTER_DEBUG if (debug) { Console.Error.WriteLine("Sending {0}\n from: {1} to: {2}\n delloc: {3}", p,prev_e,next_con,deliverlocally); } #endif return 1; } else { #if AHROUTER_DEBUG if (debug) { Console.Error.WriteLine("Not sending {0}\n from: {1}\n delloc: {2}", p,prev_e,deliverlocally); } #endif return 0; } } catch(EdgeException x) { if( !x.IsTransient ) { /* Console.Error.WriteLine(x); Console.Error.WriteLine("{0}: Edge exception encountered while sending from: {1} to: {3}, delloc: {2}", _local,prev_e,deliverlocally, next_con); */ /* * This is a permanent error * This edge gave us problems, let's try again after we've closed * that bad edge. * * Make sure the cache is flushed and we reset out nearest left * neighbor */ next_con.Edge.Close(); ConnectionTableChangeHandler(null, null); return this.Route(prev_e, p, out deliverlocally); } else { /** * In the case of a transient problem, we just drop the * packet. * @todo should we send some error message, or retry later? */ return 0; } } }
/** * Create an AHPacket representing an Error */ protected AHPacket CreateErrorPacket(Address destination, short sourcetid, short desttid, Error err) { byte[] body = new byte[1024]; //Write the our TID NumberSerializer.WriteShort(sourcetid, body, 0); //Write the other TID NumberSerializer.WriteShort(desttid, body, 2); int size = 4; size += err.CopyTo(body, 4); //Send the error: AHPacket resp = new AHPacket(0, 32, _node.Address, destination, AHPacket.Protocol.Tftp, body, 0, size); return resp; }
/** * Send an acknowledgement for the given block in the given transfer */ protected void SendAck(Request req, int block) { byte[] body = new byte[8]; //Write the our TID NumberSerializer.WriteShort(req.LocalTID, body, 0); //Write the other TID NumberSerializer.WriteShort(req.PeerTID, body, 2); //Write the OP: NumberSerializer.WriteShort((short)Opcode.Ack, body, 4); //Write the Block number: NumberSerializer.WriteShort((short)block, body, 6); AHPacket resp = new AHPacket(0, 32, _node.Address, req.Peer, AHPacket.Protocol.Tftp, body); _node.Send(resp); }
/** * Implementing from IAHPacketHandler * This is where we do the meat of the operating */ public void HandleAHPacket(object node, AHPacket p, Edge from) { Node n = (Node)node; Stream packet_data = p.PayloadStream; short peer_tid = NumberSerializer.ReadShort(packet_data); short local_tid = NumberSerializer.ReadShort(packet_data); Opcode op = (Opcode)NumberSerializer.ReadShort(packet_data); /** * If there is any Error, an exception is thrown and the * Error is sent to the node which sent us this packet */ Error err = null; //This is the Request to which this packet is associated Request req = null; try { if( local_tid == DefaultTID ) { /** * This is a new request being made to us from a remote node */ lock( _sync ) { //Check to see if this request is a duplicate: foreach(Request openr in _open_requests) { if( openr.Peer.Equals(p.Source) && (openr.PeerTID == peer_tid) ) { req = openr; /** * We need to send an Error response when we * get the same TID from the same Address. * This must be a duplicate packet. */ err = new Error(Error.Code.NotDefined, "Duplicate Source TID"); throw new Exception(); } } } //This is a new operation local_tid = GetNextTID(); //We need to parse the request and assign a new TID to this transfer req = new Request(peer_tid, local_tid, op, p.Source, packet_data); //If we get here, this is a new request IAcceptor acc = null; if( op == Opcode.ReadReq ) { acc = _read_acc; } else if( op == Opcode.WriteReq ) { acc = _write_acc; } if( acc != null ) { _open_requests.Add(req); acc.Accept(req, this); } else { //Something bad happened err = new Error(Error.Code.IllegalOp, "Unknown Opcode"); throw new Exception(); } } else if (_tid_to_status.ContainsKey(local_tid) ) { //This is continuing an existing transfer Status stat = (Status)_tid_to_status[local_tid]; if( stat == null) { /** * Status is null until a Request is accepted or denied. * This request is either a (lucky) bug or an attack. * You see, there is no way for the Peer to know which * TID we are using when status is null. This only happens * when a TID has been assigned locally, but not yet sent * over the network. Hence, the Peer made a lucky guess. */ Error error = new Error(Error.Code.UnknownTID, "say what?"); AHPacket resp = CreateErrorPacket(p.Source, DefaultTID, peer_tid, error); _node.Send(resp); } else { req = stat.Request; short block; switch(op) { case Opcode.Data: ///@todo consider carefully that this works in both directions ///@todo make all blocks ushort (so we can use an int == -1 to initialize) block = NumberSerializer.ReadShort(packet_data); /** * When data comes, we send an Ack */ lock( stat ) { if( stat.LastBlockNumber == block ) { /* * This is a block we have already seen */ SendAck(req, block); } else if( stat.PendingBlock == block ) { //We are already dealing with this data //So, we do nothing here } else { /* * This is a new Data block to us! * Write it to disk and then send the Ack */ StreamState ws = new StreamState(); stat.StartBlock(block, ws); //This is new data we have not yet seen ws.Stat = stat; ws.Block = block; ws.Data = new byte[ stat.Request.Blksize ]; ws.Offset = 0; //The packet data is a MemoryStream which never blocks: ws.Size = packet_data.Read(ws.Data, 0, stat.Request.Blksize); stat.Data.BeginWrite(ws.Data, ws.Offset, ws.Size, new AsyncCallback(this.WriteHandler), ws); } } break; case Opcode.Ack: block = NumberSerializer.ReadShort(packet_data); /** * When an Ack comes, we know our last Data * has made it across and we send the next Data * We complete the block associated with that, * and if we are not done, we start the next read */ lock( stat ) { StreamState sent = (StreamState)stat.PendingState; bool finished = stat.CompleteBlock(block, sent.Size); if( !finished ) { //Do the next read: StreamState rs = new StreamState(); int new_block = block + 1; stat.StartBlock(new_block, rs); rs.Stat = stat; rs.Block = new_block; rs.Data = new byte[ stat.Request.Blksize ]; rs.Offset = 0; stat.Data.BeginRead(rs.Data, rs.Offset, stat.Request.Blksize, new AsyncCallback(this.ReadHandler), rs); } } break; case Opcode.Error: Error.Code code = (Error.Code)NumberSerializer.ReadShort(packet_data); string message = ReadAsciiStringFrom(packet_data); //Things did not work out for us stat.SetError(new Error(code, message)); break; default: err = new Error(Error.Code.IllegalOp, "Unknown Opcode"); throw new Exception(); }//End of switch }//End of case where stat != null }//End of case where TID is known else { //Never heard of this TID! Error error = new Error(Error.Code.UnknownTID, "say what?"); AHPacket resp = CreateErrorPacket(p.Source, DefaultTID, peer_tid, error); _node.Send(resp); } } catch(Exception x) { /** * If there has been any Exception or Error, we will wind up here * in which case we send an error response and release this TID. */ if( err == null ) { //Set the error err = new Error(Error.Code.NotDefined, x.ToString() ); } SendError(req, err); ReleaseTID(local_tid); } }
/** * Implementing from IAHPacketHandler */ public bool HandlesAHProtocol(AHPacket.Protocol type) { return (type == AHPacket.Protocol.Tftp); }
/** * Handle sending of an edge synchronization. * @param e tunnel edge. * @param forwarders list of forwarders for the tunnel edge. */ public void HandleSyncSend(Edge e, IEnumerable forwarders) { if (0 == _running) { //do nothing return; } TunnelEdge tun_edge = (TunnelEdge)e; Packet p = null; using( MemoryStream ms = new MemoryStream() ) { ms.WriteByte((byte) MessageType.EdgeSync); NumberSerializer.WriteInt(tun_edge.ID, ms); NumberSerializer.WriteInt(tun_edge.RemoteID, ms); ArrayList args = new ArrayList(); foreach (Address addr in forwarders) { //add forwarding addresses args.Add( addr.ToMemBlock() ); } AdrConverter.Serialize(args, ms); p = new AHPacket(1, 2, _node.Address, tun_edge.Target, AHPacket.AHOptions.Exact, AHPacket.Protocol.Tunneling, ms.ToArray()); } ArrayList packet_senders = tun_edge.PacketSenders; int r_idx = _rand.Next(0, packet_senders.Count); int attempts = packet_senders.Count; while (attempts-- > 0) { ISender sender = null; try { int this_idx = (r_idx + attempts) % packet_senders.Count; sender = (ISender) packet_senders[this_idx]; #if TUNNEL_DEBUG Console.Error.WriteLine("Sending edge sync on base connection: {0}", _node.ConnectionTable.GetConnection((Edge) sender)); #endif sender.Send(p); return; } catch(EdgeClosedException) { /* * Just ignore it an move on to the next sender */ } catch(SendException x) { //Just ignore it an move on to the next sender } catch(Exception ex) { if(ProtocolLog.UdpEdge.Enabled) ProtocolLog.Write(ProtocolLog.Exceptions, String.Format( "Error sending edge sync on packet_sender: {0}, {1}", sender, ex)); } } }
/** * Here we handle routing AHPackets */ public void HandleData(MemBlock data, ISender ret_path, object state) { /* * Unfortunately, the old code needs the full header intact, and * we have already eaten a byte of it, put it back: */ MemBlock full_packet = data.ExtendHead(1); AHPacket p = new AHPacket(full_packet); //Route avoiding the edge we got the packet from: IRouter router = null; if( p.Destination.Class == 0 ) { router = _ah_router; } else { router = _d_router; } Edge edge_rec_from = ret_path as Edge; bool deliver_locally; router.Route(edge_rec_from, p, out deliver_locally); if( deliver_locally ) { //Send a response exactly back to the node that sent to us ISender resp_send = new AHSender(_n, ret_path, p.Source, _n.DefaultTTLFor(p.Source), AHPacket.AHOptions.Exact); //data: _n.HandleData( data.Slice(AHPacket.HeaderLength), resp_send, this); } }
/** * This method creates an instance of a tunnel edge to a remote node, given its * tunnel transport URI. * @param ta TransportAddress to create an edge to * @param ecb the EdgeCreationCallback to call when done * @throw EdgeException if we try to call this before calling * Start. */ public override void CreateEdgeTo(TransportAddress ta, EdgeCreationCallback ecb) { try { if (!IsStarted) { throw new EdgeException("TunnelEdgeListener not started"); } else if (0 == _running) { throw new EdgeException("TunnelEdgeListener not running"); } else if (ta.TransportAddressType != this.TAType) { throw new EdgeException(ta.TransportAddressType.ToString() + " is not my type: " + this.TAType.ToString()); } else { #if TUNNEL_DEBUG Console.Error.WriteLine("CreateEdgeTo TunnelEdge to: {0}", ta); #endif TunnelTransportAddress tun_ta = ta as TunnelTransportAddress; ArrayList forwarders = new ArrayList(); ArrayList forwarding_edges = new ArrayList(); #if TUNNEL_DEBUG Console.Error.WriteLine("TunnelEdgeListener: Finding structured connections to tunnel over"); #endif IEnumerable struc_cons = _node.ConnectionTable.GetConnections(ConnectionType.Structured); if (struc_cons == null) { #if TUNNEL_DEBUG Console.Error.WriteLine("List of structured connections is null"); #endif } #if TUNNEL_DEBUG Console.Error.WriteLine("TunnelEdgeListener: Browsing list of structured connections"); #endif foreach (Connection con in struc_cons) { #if TUNNEL_DEBUG Console.Error.WriteLine("TunnelEdgeListener: Testing : {0}", con.Address); #endif if (con.Edge.TAType == TransportAddress.TAType.Tunnel) { #if TUNNEL_DEBUG Console.Error.WriteLine("Cannot tunnel over tunnel: " + con.Address.ToString()); #endif continue; } if (!tun_ta.ContainsForwarder(con.Address)) { #if TUNNEL_DEBUG Console.Error.WriteLine("Cannot tunnel over connection: " + con.Address.ToString()); #endif continue; } #if TUNNEL_DEBUG Console.Error.WriteLine("Can tunnel over connection: " + con.Address.ToString()); #endif forwarders.Add(con.Address); forwarding_edges.Add(con.Edge); } if (forwarders.Count < MIN_FORWARDERS) { ecb(false, null, new EdgeException("Cannot create edge over TA: " + tun_ta + ", not many forwarders")); return; } tun_ta = new TunnelTransportAddress(tun_ta.Target, forwarders); //choose a locally unique id lock( _sync ) { //Get a random ID for this edge: int localid; int remoteid = 0; do { localid = _rand.Next(); //Make sure we don't have negative ids if( localid < 0 ) { localid = ~localid; } } while( _id_ht.Contains(localid) || localid == 0 ); //looks like the new edge is ready TunnelEdge e = new TunnelEdge(this, false, _node, tun_ta.Target, forwarders, localid, remoteid); #if TUNNEL_DEBUG Console.Error.WriteLine("Creating an instance of TunnelEdge: {0}", e); Console.Error.WriteLine("remoteid: {0}, localid: {1}", remoteid, localid); #endif _id_ht[localid] = e; //we will defer the new edge event for later //when we actually get a response //now build the packet payload Packet p = null; using(MemoryStream ms = new MemoryStream()) { ms.WriteByte((byte) MessageType.EdgeRequest); NumberSerializer.WriteInt(localid, ms); NumberSerializer.WriteInt(remoteid, ms); #if TUNNEL_DEBUG Console.Error.WriteLine("Written off type, localid, remoteid"); #endif ArrayList args = new ArrayList(); //add the target address byte[] addr_bytes = new byte[Address.MemSize]; _node.Address.CopyTo(addr_bytes); args.Add(addr_bytes.Clone()); #if TUNNEL_DEBUG Console.Error.WriteLine("Added target address"); #endif foreach (Address fwd in forwarders) { //add forwarding addresses fwd.CopyTo(addr_bytes); args.Add(addr_bytes.Clone()); #if TUNNEL_DEBUG Console.Error.WriteLine("Added a forwarding address"); #endif } #if TUNNEL_DEBUG Console.Error.WriteLine("Creating a memory stream holding the payload"); #endif AdrConverter.Serialize(args, ms); p = new AHPacket(1, 2, _node.Address, tun_ta.Target, AHPacket.AHOptions.Exact, AHPacket.Protocol.Tunneling, ms.ToArray()); } #if TUNNEL_DEBUG Console.Error.WriteLine("Created a request packet."); #endif EdgeCreationState ecs = new EdgeCreationState(localid, forwarding_edges, p, ecb); _ecs_ht[localid] = ecs; #if TUNNEL_DEBUG Console.Error.WriteLine("Created an edge creation state for the tunnel edge: {0}", e); #endif } } //we will defer this sending to next heartbeat; an artificial delay from out own side } catch(Exception e) { ecb(false, null, e); } }
/** * When we get an EdgeRequest message, this is where we handle it. * @param remoteid remote id for the edge. * @param localid local id for the edge. * @param rest_of_payload control message. * @param return_path return path for the packet */ protected void HandleEdgeRequest(int remoteid, int localid, MemBlock rest_of_payload, ISender return_path) { #if TUNNEL_DEBUG Console.Error.WriteLine("Receiving edge request"); #endif //probably a new incoming edge bool is_new_edge = true; bool send_edge_event = false; TunnelEdge e = null; ArrayList args = (ArrayList) AdrConverter.Deserialize(rest_of_payload); Address target = AddressParser.Parse(MemBlock.Reference((byte[]) args[0])); //list of packet forwarders ArrayList forwarders = new ArrayList(); for (int i = 1; i < args.Count; i++) { forwarders.Add(AddressParser.Parse(MemBlock.Reference((byte[]) args[i]))); } //it is however possible that we have already created the edge locally lock( _sync ) { TunnelEdge e_dup = (TunnelEdge) _remote_id_ht[remoteid]; if (e_dup != null) { TunnelTransportAddress remote_ta = new TunnelTransportAddress(target, forwarders); //compare TAs TunnelTransportAddress e_rta = e_dup.RemoteTA as TunnelTransportAddress; if (e_rta != null && e_rta.Target.Equals( remote_ta.Target ) ) { //the fellow sent a duplicate edge request is_new_edge = false; #if TUNNEL_DEBUG Console.Error.WriteLine("Duplicate edge request: from {0}", remote_ta); #endif //but do send a response back //we also have to send a response back now } else { //someone else guessed the same id on its side //still okay, we can generate a unqiue id locally } } else { //this is the first edge request from a node and also //has a unique id on its side } if(is_new_edge) { do { localid = _rand.Next(); //Make sure not to use negative ids if( localid < 0 ) { localid = ~localid; } } while( _id_ht.Contains(localid) || localid == 0 ); //create an edge e = new TunnelEdge(this, true, _node, target, forwarders, localid, remoteid); #if TUNNEL_DEBUG Console.Error.WriteLine("Creating an instance of TunnelEdge: {0}", e); Console.Error.WriteLine("remoteid: {0}, localid: {1}", remoteid, localid); #endif _id_ht[localid] = e; _remote_id_ht[remoteid] = e; try { e.CloseEvent += this.CloseHandler; } catch { CloseHandler(e, null); throw; } #if TUNNEL_DEBUG Console.Error.WriteLine("announcing tunnel edge (incoming): {0}", e); #endif send_edge_event = true; } }//Drop the lock /* * No matter what, we send a response back now */ Packet p = null; using(MemoryStream ms = new MemoryStream()) { ms.WriteByte((byte) MessageType.EdgeResponse); NumberSerializer.WriteInt(localid, ms); NumberSerializer.WriteInt(remoteid, ms); //overwrite the first address in the edge response args[0] = _node.Address.ToMemBlock(); AdrConverter.Serialize(args, ms); p = new AHPacket(1, 2, _node.Address, target, AHPacket.AHOptions.Exact, AHPacket.Protocol.Tunneling, ms.ToArray()); } //send using the edge we received data on #if TUNNEL_DEBUG Console.Error.WriteLine("Sending edge response: {0}", p); #endif try { AHSender ahs = (AHSender)return_path; Edge from = (Edge)ahs.ReceivedFrom; from.Send(p); #if TUNNEL_DEBUG } catch (Exception ex) { Console.Error.WriteLine(ex); #else } catch (Exception) { #endif } finally { if( send_edge_event ) { SendEdgeEvent(e); } } }
static void Main(string[] args) { //log.Debug( "Starting the Brunet Echo Tester" ); String config_file = args[0]; NetworkConfiguration network_configuration = NetworkConfiguration.Deserialize(config_file); int port_selection = Convert.ToInt32(args[1]); //There will be 10 different ports available for use: 0, 1, 2.. //for example, node 0 on a machine will use port_selection # 0, node 1 on a machine will use port_selection # 1 ///There will be multiple BruNet nodes on the same machine. The following is a list of possible ports used int list_size = 150; int [] port_list = new int[list_size]; for(int i = 0; i < list_size; i++){ port_list[i] = 25000 + i; } ///The line below is used when there is only one node per machine //int local_host_index = network_configuration.GetLocalHostIndex(); int desired_port = port_list[port_selection]; int local_host_index = network_configuration.GetLocalHostIndex(desired_port); NodeConfiguration this_node_configuration = (NodeConfiguration)network_configuration.Nodes[local_host_index]; TransportAddressConfiguration local_ta_configuration = (TransportAddressConfiguration)this_node_configuration.TransportAddresses[0]; short port = local_ta_configuration.Port; SHA1 sha = new SHA1CryptoServiceProvider(); String local_ta = local_ta_configuration.GetTransportAddressURI(); //We take the local transport address plus the port number to be hashed to obtain a random AHAddress byte[] hashedbytes = sha.ComputeHash(Encoding.UTF8.GetBytes(local_ta + port)); //inforce type 0 hashedbytes[Address.MemSize - 1] &= 0xFE; AHAddress _local_ahaddress = new AHAddress(hashedbytes); Node this_node = new StructuredNode( _local_ahaddress ); ///Node this_node = new HybridNode( new AHAddress( new BigInteger( 2*(local_host_index+1) ) ) ); String file_string = "./data/brunetadd" + Convert.ToString(desired_port) + ".log"; StreamWriter sw = new StreamWriter(file_string, false); sw.WriteLine( "local_address " + this_node.Address.ToBigInteger().ToString() + " " + Dns.GetHostName() + ":" + port); sw.Close(); if ( local_ta_configuration.Protocol == "tcp" ) { this_node.AddEdgeListener( new TcpEdgeListener(port) ); } else if( local_ta_configuration.Protocol == "udp" ) { this_node.AddEdgeListener( new UdpEdgeListener(port) ); } int remote_node_index = local_host_index-1; int num_remote_ta = 20; //20 nodes on the list to try to bootstrap to if (local_host_index!=0) { NodeConfiguration remote_node_configuration = (NodeConfiguration)network_configuration.Nodes[0]; TransportAddressConfiguration remote_ta_configuration = (TransportAddressConfiguration)remote_node_configuration.TransportAddresses[0]; String remote_ta = remote_ta_configuration.GetTransportAddressURI(); this_node.RemoteTAs.Add( TransportAddressFactory.CreateInstance( remote_ta ) ); } while ( (remote_node_index>=0) && (num_remote_ta>=0) ) { NodeConfiguration remote_node_configuration = (NodeConfiguration)network_configuration.Nodes[remote_node_index]; TransportAddressConfiguration remote_ta_configuration = (TransportAddressConfiguration)remote_node_configuration.TransportAddresses[0]; String remote_ta = remote_ta_configuration.GetTransportAddressURI(); this_node.RemoteTAs.Add( TransportAddressFactory.CreateInstance( remote_ta ) ); System.Console.WriteLine("Adding {0}", remote_ta); remote_node_index--; num_remote_ta--; } /* NodeConfiguration remote_node_configuration = (NodeConfiguration)network_configuration.Nodes[remote_node_index]; TransportAddressConfiguration remote_ta_configuration = (TransportAddressConfiguration)remote_node_configuration.TransportAddresses[0]; String remote_ta = remote_ta_configuration.GetTransportAddressURI(); this_node.RemoteTAs.Add( TransportAddressFactory.CreateInstance( remote_ta ) );*/ EchoTester echo_printer = new EchoTester(); this_node.GetTypeSource(PType.Protocol.Echo).Subscribe(echo_printer, this_node); #if PLAB_LOG ///Initialize Brunet logger BrunetLogger bl = new BrunetLogger(desired_port, (AHAddress)this_node.Address); this_node.Logger = bl; #endif this_node.Connect(); //Send a "hello message" to a random neighbor ASCIIEncoding ascii = new ASCIIEncoding(); //Make the target addresses AHAddress target = new AHAddress( new BigInteger( 2*(remote_node_index+1) ) ); string hello_msg = "hello, brunet"; int byteCount = ascii.GetByteCount(hello_msg); byte[] bytes = new byte[byteCount + 1]; ascii.GetBytes(hello_msg, 0, hello_msg.Length, bytes, 1); // update the payload // This is a request, so the first byte is greater than zero bytes[0] = (byte) 1; AHPacket p = new AHPacket(0, 30, this_node.Address, target, AHPacket.Protocol.Echo, bytes); ///RDP Experiment: sending the echo packet periodically /* int seq = 0; while(true){ int start_time = System.DateTime.Now.Millisecond; this_node.Send(p); Console.WriteLine("Seq = {0}, Start Time = {1}", seq, start_time); System.Threading.Thread.Sleep(10000); seq++; }*/ ///The following is a while-loop for the local node to Brunet-ping all other nodes in the network System.Threading.Thread.Sleep(60000); ///IMPORTANT: change this parameter so we wait longer for larger network Random uid_generator = new Random( DateTime.Now.Millisecond + local_ta.GetHashCode() + port); bytes = new byte[5]; int target_index = 0, num_pings = 10, wait_time = 10000; //the wait_time is in ms double ping_time; PingWrapper pw = new PingWrapper(); while( target_index < network_configuration.Nodes.Count ){ if(target_index != local_host_index){///we do not ping the local machine NodeConfiguration target_node_configuration = (NodeConfiguration)network_configuration.Nodes[target_index]; TransportAddressConfiguration target_ta_configuration = (TransportAddressConfiguration)target_node_configuration.TransportAddresses[0]; short target_port = target_ta_configuration.Port; double ping1 = pw.Ping(target_ta_configuration.Address, 10000); double ping2 = pw.Ping(target_ta_configuration.Address, 10000); if(ping1 >= 0 || ping2 >= 0){ //we gather the data only when the node is ping-able sha = new SHA1CryptoServiceProvider(); String target_ta = target_ta_configuration.GetTransportAddressURI(); //We take the transport address plus the port number to be hashed to obtain a random AHAddress hashedbytes = sha.ComputeHash(Encoding.UTF8.GetBytes(target_ta + target_port)); //inforce type 0 hashedbytes[Address.MemSize - 1] &= 0xFE; AHAddress _target_ahaddress = new AHAddress(hashedbytes); #if PLAB_LOG ///Write the header to a log file bl.LogBPHeader(local_ta_configuration.Address, local_ta_configuration.Port, target_ta_configuration.Address, target_ta_configuration.Port); bl.LogPingHeader(local_ta_configuration.Address, local_ta_configuration.Port, target_ta_configuration.Address, target_ta_configuration.Port); #endif for(int i = 0; i < num_pings; i++){ //ping and Brunet-ping the target node for a number of times int uid = uid_generator.Next(); //this is the unique id of the packet // update the payload // This is a request, so the first byte is greater than zero bytes[0] = (byte) 1; NumberSerializer.WriteInt(uid, bytes, 1); p = new AHPacket(0, 30, this_node.Address, _target_ahaddress, AHPacket.Protocol.Echo, bytes); this_node.Send(p); ping_time = pw.Ping(target_ta_configuration.Address, wait_time); //wait wait_time number of ms #if PLAB_LOG bl.LogPing(ping_time); #else System.Console.WriteLine("Ping time: {0}",ping_time); #endif System.Threading.Thread.Sleep(wait_time); }//end of for-loop } }//end of if-loop target_index++; }//end of while-loop }
public void Test() { /* * Make some random packets and see if they round trip properly. */ RandomNumberGenerator rng = new RNGCryptoServiceProvider(); Random simple_rng = new Random(); for(int i = 0; i < 100; i++) { AHAddress source = new AHAddress(rng); AHAddress dest = new AHAddress(rng); short ttl = (short)simple_rng.Next(Int16.MaxValue); short hops = (short)simple_rng.Next(Int16.MaxValue); ushort options = (ushort)simple_rng.Next(UInt16.MaxValue); byte[] bin_prot = new byte[ simple_rng.Next(1,4) ]; simple_rng.NextBytes(bin_prot); string random_prot = Base32.Encode( bin_prot ); byte[] payload = new byte[ simple_rng.Next(1,1024) ]; simple_rng.NextBytes(payload); AHPacket p = new AHPacket(hops, ttl, source, dest, options, random_prot, payload); AssertEqualAHPackets(p, RoundTrip(p) ); AHPacket phops = new AHPacket((short)(hops + 1), ttl, source, dest, options, random_prot, payload); AHPacket inc_hops = p.IncrementHops(); AssertEqualAHPackets(phops, inc_hops ); //Round trip them all: AssertEqualAHPackets(p, RoundTrip(p)); AssertEqualAHPackets(inc_hops, RoundTrip(inc_hops)); AssertEqualAHPackets(phops, RoundTrip(phops)); } }
public AHPacket RoundTrip(AHPacket p) { byte[] binary_packet = new byte[ p.Length ]; p.CopyTo( binary_packet, 0); return new AHPacket(MemBlock.Reference(binary_packet)); }
public void AssertEqualAHPackets(AHPacket p1, AHPacket p2) { Assert.AreEqual(p1.Hops, p2.Hops, "Hops"); Assert.AreEqual(p1.Ttl, p2.Ttl, "Ttl"); Assert.AreEqual(p1.Source, p2.Source, "Source"); Assert.AreEqual(p1.Destination, p2.Destination, "Dest"); Assert.AreEqual(p1.Options, p2.Options, "Options"); Assert.AreEqual(p1.PayloadType, p2.PayloadType, "Payload Type"); byte[] payload1 = p1.PayloadStream.ToArray(); byte[] payload2 = p2.PayloadStream.ToArray(); Assert.AreEqual(payload1.Length, payload2.Length, "Payload length"); for(int i = 0; i < payload1.Length; i++) { Assert.AreEqual(payload1[i], payload2[i], "Payload[" + i.ToString() + "]"); } Assert.AreEqual(p1.Length, p2.Length, "Total Length"); }
/** * @returns a new AHPacket with the hops field incremented */ public AHPacket IncrementHops() { AHPacket p = new AHPacket(); p._buffer = _buffer; p._hops = (short)(_hops + 1); p._ttl = _ttl; p._source = _source; p._destination = _destination; p._options = _options; p._pt = _pt; return p; }