상속: Edge
예제 #1
0
        /**
         * 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);
            }
        }
예제 #2
0
        protected void SendControlPacket(EndPoint end, int remoteid, int localid,
                                         ControlCode c, object state)
        {
            using (MemoryStream ms = new MemoryStream()) {
                NumberSerializer.WriteInt((int)c, ms);
                if (c == ControlCode.EdgeDataAnnounce)
                {
                    UdpEdge e = (UdpEdge)_id_ht[localid];
                    if ((e != null) && (e.RemoteID == remoteid))
                    {
                        Hashtable t = new Hashtable();
                        t["RemoteTA"] = e.RemoteTA.ToString();
                        t["LocalTA"]  = e.LocalTA.ToString();
                        AdrConverter.Serialize(t, ms);
                    }
                    else
                    {
                        if (ProtocolLog.UdpEdge.Enabled)
                        {
                            ProtocolLog.Write(ProtocolLog.UdpEdge, String.Format(
                                                  "Problem sending EdgeData: EndPoint: {0}, remoteid: {1}, " +
                                                  "localid: {2}, Edge: {3}", end, remoteid, localid, e));
                        }
                    }
                }

                _send_queue.Enqueue(new UdpMessage(localid, ~remoteid, MemBlock.Reference(ms.ToArray()), end));
                if (ProtocolLog.UdpEdge.Enabled)
                {
                    ProtocolLog.Write(ProtocolLog.UdpEdge, String.Format(
                                          "Sending control {1} to: {0}", end, c));
                }
            }
        }
예제 #3
0
 /**
  * When a new Connection is added, we may need to update the list
  * of TAs to make sure it is not too long, and that the it is sorted
  * from most likely to least likely to be successful
  * @param e the new Edge
  * @param ta the TransportAddress our TA according to our peer
  */
 public override void UpdateLocalTAs(Edge e, TransportAddress ta)
 {
     if (e.TAType == this.TAType)
     {
         UdpEdge ue = (UdpEdge)e;
         ue.PeerViewOfLocalTA = ta;
         NatDataPoint dp = new LocalMappingChangePoint(DateTime.UtcNow, e, ta);
         Interlocked.Exchange <NatHistory>(ref _nat_hist, _nat_hist + dp);
         Interlocked.Exchange <IEnumerable>(ref _nat_tas, new NatTAs(_tas, _nat_hist));
     }
 }
예제 #4
0
        /**
         * When UdpEdge objects call Send, it calls this packet callback:
         */
        public void HandleEdgeSend(Edge from, ICopyable p)
        {
            if (_send_queue.Count > 1024)
            {
                Console.WriteLine("Send queue too big: " + _send_queue.Count);
                // This may be causing the memory leak ... not certain
                return;
//        throw new EdgeException(true, "Could not send on: " + from);
            }
            UdpEdge edge = from as UdpEdge;

            _send_queue.Enqueue(new UdpMessage(edge.ID, edge.RemoteID, p, edge.End));
        }
예제 #5
0
        /**
         * When UdpEdge objects call Send, it calls this packet
         * callback:
         * @todo The previous interface did not throw an exception to a user
         * since the send was called in another thread.  All code that calls this
         * could be updated to handle exceptions that the socket might throw.
         */
        public void HandleEdgeSend(Edge from, ICopyable p)
        {
            UdpEdge sender = (UdpEdge)from;

            lock (_send_sync) {
                //Write the IDs of the edge:
                //[local id 4 bytes][remote id 4 bytes][packet]
                NumberSerializer.WriteInt(sender.ID, _send_buffer, 0);
                NumberSerializer.WriteInt(sender.RemoteID, _send_buffer, 4);
                int plength = p.CopyTo(_send_buffer, 8);
                try {
                    _s.SendTo(_send_buffer, 8 + plength, SocketFlags.None, sender.End);
                }
                catch (Exception x) {
                    bool transient = (1 == _running);
                    throw new SendException(transient, String.Format("Problem sending on: {0}", sender), x);
                }
            }
        }
예제 #6
0
        /**
         * When a UdpEdge closes we need to remove it from
         * our table, so we will know it is new if it comes
         * back.
         */
        public void CloseHandler(object edge, EventArgs args)
        {
            UdpEdge e = (UdpEdge)edge;

            lock ( _id_ht ) {
                if (_id_ht.Contains(e.ID))
                {
                    _id_ht.Remove(e.ID);
                    object re = _remote_id_ht[e.RemoteID];
                    if (re == e)
                    {
                        //_remote_id_ht only keeps track of incoming edges,
                        //so, there could be two edges with the same remoteid
                        //that are not equivalent.
                        _remote_id_ht.Remove(e.RemoteID);
                    }
                    NatDataPoint dp = new EdgeClosePoint(DateTime.UtcNow, e);
                    Interlocked.Exchange <NatHistory>(ref _nat_hist, _nat_hist + dp);
                    Interlocked.Exchange <IEnumerable>(ref _nat_tas, new NatTAs(_tas, _nat_hist));
                }
            }
        }
예제 #7
0
    /**
     * 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);
      }
    }
예제 #8
0
    /**
     * 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);
        }
      }
    }
예제 #9
0
        /**
         * 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);
                }
            }
        }
예제 #10
0
        /**
         * This handles lightweight control messages that may be sent
         * by UDP
         */
        protected void HandleControlPacket(int remoteid, int n_localid,
                                           MemBlock buffer, object state)
        {
            int     local_id = ~n_localid;
            UdpEdge e        = _id_ht[local_id] as UdpEdge;

            if (e == null)
            {
                return;
            }

            if (e.RemoteID == 0)
            {
                try {
                    e.RemoteID = remoteid;
                } catch {
                    return;
                }
            }

            if (e.RemoteID != remoteid)
            {
                return;
            }

            try {
                ControlCode code = (ControlCode)NumberSerializer.ReadInt(buffer, 0);
                if (ProtocolLog.UdpEdge.Enabled)
                {
                    ProtocolLog.Write(ProtocolLog.UdpEdge, String.Format(
                                          "Got control {1} from: {0}", e, code));
                }
                if (code == ControlCode.EdgeClosed)
                {
                    //The edge has been closed on the other side
                    RequestClose(e);
                    CloseHandler(e, null);
                }
                else if (code == ControlCode.EdgeDataAnnounce)
                {
                    //our NAT mapping may have changed:
                    IDictionary info =
                        (IDictionary)AdrConverter.Deserialize(buffer.Slice(4));
                    string our_local_ta = (string)info["RemoteTA"]; //his remote is our local
                    if (our_local_ta != null)
                    {
                        //Update our list:
                        TransportAddress new_ta = TransportAddressFactory.CreateInstance(our_local_ta);
                        TransportAddress old_ta = e.PeerViewOfLocalTA;
                        if (!new_ta.Equals(old_ta))
                        {
                            if (ProtocolLog.UdpEdge.Enabled)
                            {
                                ProtocolLog.Write(ProtocolLog.UdpEdge, String.Format(
                                                      "Local NAT Mapping changed on Edge: {0}\n{1} => {2}",
                                                      e, old_ta, new_ta));
                            }
                            //Looks like matters have changed:
                            this.UpdateLocalTAs(e, new_ta);

                            /**
                             * @todo, maybe we should ping the other edges sharing this
                             * EndPoint, but we need to be careful not to do some O(E^2)
                             * operation, which could easily happen if each EdgeDataAnnounce
                             * triggered E packets to be sent
                             */
                        }
                    }
                }
                else if (code == ControlCode.Null)
                {
                    //Do nothing in this case
                }
            }
            catch (Exception x) {
                //This could happen if this is some control message we don't understand
                if (ProtocolLog.Exceptions.Enabled)
                {
                    ProtocolLog.Write(ProtocolLog.Exceptions, x.ToString());
                }
            }
        }