/** * Implements the EdgeListener function to * create edges of this type. */ public override void CreateEdgeTo(TransportAddress ta, EdgeCreationCallback ecb) { Edge e = null; Exception ex = null; if (!IsStarted) { ex = new EdgeException("UdpEdgeListener is not started"); } else if (ta.TransportAddressType != this.TAType) { ex = new EdgeException(ta.TransportAddressType.ToString() + " is not my type: " + this.TAType.ToString()); } else if (_ta_auth.Authorize(ta) == TAAuthorizer.Decision.Deny) { ex = 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)); try { /* Tell me when you close so I can clean up the table */ e.CloseEvent += this.CloseHandler; } catch (Exception x) { e = null; ex = x; } } if (e != null) { ecb(true, e, null); } else { 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) { IPEndPoint this_end = (IPEndPoint)end; edge.End = new IPEndPoint(this_end.Address, this_end.Port); 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); // Stun support SendControlPacket(end, remoteid, localid, ControlCode.EdgeDataAnnounce, state); } 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); } } }