/** * Implements the EdgeListener function to * create edges of this type. */ public override void CreateEdgeTo(TransportAddress ta, EdgeCreationCallback ecb) { Edge e = null; try { if( !IsStarted ) { throw new EdgeException("UdpEdgeListener is not started"); } else if( ta.TransportAddressType != this.TAType ) { throw new EdgeException(ta.TransportAddressType.ToString() + " is not my type: " + this.TAType.ToString() ); } else if( _ta_auth.Authorize(ta) == TAAuthorizer.Decision.Deny ) { //Too bad. Can't make this edge: throw new EdgeException( ta.ToString() + " is not authorized"); } else { IPAddress first_ip = ((IPTransportAddress) ta).GetIPAddress(); IPEndPoint end = new IPEndPoint(first_ip, ((IPTransportAddress) ta).Port); /* We have to keep our mapping of end point to edges up to date */ lock( _id_ht ) { //Get a random ID for this edge: int id; do { id = _rand.Next(); //Make sure we don't have negative ids if( id < 0 ) { id = ~id; } } while( _id_ht.Contains(id) || id == 0 ); e = new UdpEdge(this, false, end, _local_ep, id, 0); _id_ht[id] = e; } NatDataPoint dp = new NewEdgePoint(DateTime.UtcNow, e); Interlocked.Exchange<NatHistory>(ref _nat_hist, _nat_hist + dp); Interlocked.Exchange<IEnumerable>(ref _nat_tas, new NatTAs( _tas, _nat_hist )); /* Tell me when you close so I can clean up the table */ e.CloseEvent += this.CloseHandler; ecb(true, e, null); } } catch(Exception ex) { if( e != null ) { //Clean up the edge CloseHandler(e, null); } ecb(false, null, ex); } }
/** * This reads a packet from buf which came from end, with * the given ids */ protected void HandleDataPacket(int remoteid, int localid, MemBlock packet, EndPoint end, object state) { bool read_packet = true; bool is_new_edge = false; //It is threadsafe to read from Hashtable UdpEdge edge = (UdpEdge)_id_ht[localid]; if( localid == 0 ) { //This is a potentially a new incoming edge is_new_edge = true; //Check to see if it is a dup: UdpEdge e_dup = (UdpEdge)_remote_id_ht[remoteid]; if( e_dup != null ) { //Lets check to see if this is a true dup: if( e_dup.End.Equals( end ) ) { //Same id from the same endpoint, looks like a dup... is_new_edge = false; //Reuse the existing edge: edge = e_dup; } else { //This is just a coincidence. } } if( is_new_edge ) { TransportAddress rta = TransportAddressFactory.CreateInstance(this.TAType,(IPEndPoint)end); if( _ta_auth.Authorize(rta) == TAAuthorizer.Decision.Deny ) { //This is bad news... Ignore it... ///@todo perhaps we should send a control message... I don't know is_new_edge= false; read_packet = false; if(ProtocolLog.UdpEdge.Enabled) ProtocolLog.Write(ProtocolLog.UdpEdge, String.Format( "Denying: {0}", rta)); } else { //We need to assign it a local ID: lock( _id_ht ) { /* * Now we need to lock the table so that it cannot * be written to by anyone else while we work */ do { localid = _rand.Next(); //Make sure not to use negative ids if( localid < 0 ) { localid = ~localid; } } while( _id_ht.Contains(localid) || localid == 0 ); /* * We copy the endpoint because (I think) .Net * overwrites it each time. Since making new * edges is rare, this is better than allocating * a new endpoint each time */ IPEndPoint this_end = (IPEndPoint)end; IPEndPoint my_end = new IPEndPoint(this_end.Address, this_end.Port); edge = new UdpEdge(_send_handler, true, my_end, _local_ep, localid, remoteid); _id_ht[localid] = edge; _remote_id_ht[remoteid] = edge; } } } } else if ( edge == null ) { /* * This is the case where the Edge is not a new edge, * but we don't know about it. It is probably an old edge * that we have closed. We can ignore this packet */ read_packet = false; //Send a control packet SendControlPacket(end, remoteid, localid, ControlCode.EdgeClosed, state); } else if ( edge.RemoteID == 0 ) { /* This is the response to our edge creation */ edge.RemoteID = remoteid; } else if( edge.RemoteID != remoteid ) { /* * This could happen as a result of packet loss or duplication * on the first packet. We should ignore any packet that * does not have both ids matching. */ read_packet = false; //Tell the other guy to close this ignored edge SendControlPacket(end, remoteid, localid, ControlCode.EdgeClosed, state); edge = null; } if( (edge != null) && !edge.End.Equals(end) ) { //This happens when a NAT mapping changes if(ProtocolLog.UdpEdge.Enabled) ProtocolLog.Write(ProtocolLog.UdpEdge, String.Format( "Remote NAT Mapping changed on Edge: {0}\n{1} -> {2}", edge, edge.End, end)); //Actually update: TransportAddress rta = TransportAddressFactory.CreateInstance(this.TAType,(IPEndPoint)end); if( _ta_auth.Authorize(rta) != TAAuthorizer.Decision.Deny ) { edge.End = end; NatDataPoint dp = new RemoteMappingChangePoint(DateTime.UtcNow, edge); Interlocked.Exchange<NatHistory>(ref _nat_hist, _nat_hist + dp); Interlocked.Exchange<IEnumerable>(ref _nat_tas, new NatTAs( _tas, _nat_hist )); //Tell the other guy: SendControlPacket(end, remoteid, localid, ControlCode.EdgeDataAnnounce, state); } else { /* * Looks like the new TA is no longer authorized. */ SendControlPacket(end, remoteid, localid, ControlCode.EdgeClosed, state); RequestClose(edge); CloseHandler(edge, null); } } if( is_new_edge ) { try { NatDataPoint dp = new NewEdgePoint(DateTime.UtcNow, edge); Interlocked.Exchange<NatHistory>(ref _nat_hist, _nat_hist + dp); Interlocked.Exchange<IEnumerable>(ref _nat_tas, new NatTAs( _tas, _nat_hist )); edge.CloseEvent += this.CloseHandler; //If we make it here, the edge wasn't closed, //go ahead and process it. SendEdgeEvent(edge); } catch { //Make sure this edge is closed and we are done with it. RequestClose(edge); CloseHandler(edge, null); read_packet = false; //This was a new edge, so the other node has our id as zero, send //with that localid: SendControlPacket(end, remoteid, 0, ControlCode.EdgeClosed, state); } } if( read_packet ) { //We have the edge, now tell the edge to announce the packet: try { edge.ReceivedPacketEvent(packet); } catch(EdgeClosedException) { SendControlPacket(end, remoteid, localid, ControlCode.EdgeClosed, state); //Make sure we record that this edge has been closed CloseHandler(edge, null); } } }