Package net.tomp2p.relay

Source Code of net.tomp2p.relay.BaseRelayForwarderRPC

package net.tomp2p.relay;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;

import net.tomp2p.connection.PeerConnection;
import net.tomp2p.connection.PeerException;
import net.tomp2p.connection.Responder;
import net.tomp2p.futures.BaseFutureAdapter;
import net.tomp2p.futures.FutureDone;
import net.tomp2p.message.Message;
import net.tomp2p.message.Message.Type;
import net.tomp2p.message.NeighborSet;
import net.tomp2p.p2p.Peer;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.peers.PeerMap;
import net.tomp2p.peers.PeerStatistic;
import net.tomp2p.peers.PeerStatusListener;
import net.tomp2p.rpc.DispatchHandler;
import net.tomp2p.rpc.NeighborRPC;
import net.tomp2p.rpc.RPC;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Abstract class that provides the basic functionality to handle relay requests
* at the relay server. It also acts as a dispatcher for different kinds
* of messages.
*
* The RelayForwarder is responsible for forwarding all messages that are
* received on a relay peer, but are intended for an unreachable peer that is
* connected to the relay peer. Every unreachable node has an own instance of
* this class at the relay server.
*
* @author Nico Rutishauser
* @author Raphael Voellmy
*
*/
public abstract class BaseRelayForwarderRPC extends DispatchHandler implements PeerStatusListener {

  private final static Logger LOG = LoggerFactory.getLogger(BaseRelayForwarderRPC.class);

  private final Number160 relayPeerId;
  private PeerAddress unreachablePeer;
  private List<Map<Number160, PeerStatistic>> peerMap = null;

  public BaseRelayForwarderRPC(Peer peer, PeerAddress unreachablePeer, RelayType relayType) {
    super(peer.peerBean(), peer.connectionBean());
    this.unreachablePeer = unreachablePeer.changeRelayed(true).changeSlow(relayType.isSlow());
    this.relayPeerId = peer.peerID();
  }

  public final PeerAddress unreachablePeerAddress() {
    return unreachablePeer;
  }

  protected final Number160 unreachablePeerId() {
    return unreachablePeer.peerId();
  }

  @Override
  public final boolean peerFailed(PeerAddress remotePeer, PeerException exception) {
    // not handled here
    return false;
  }

  @Override
  public final boolean peerFound(PeerAddress remotePeer, PeerAddress referrer, PeerConnection peerConnection) {
    if (referrer == null || remotePeer.equals(referrer)) {
      // if firsthand (referrer is null), then full trust.
      // if second hand and a stable peerconnection, we can trust as well

      if (remotePeer.peerId().equals(unreachablePeerId()) && remotePeer.isRelayed()) {
        // we got new information about this peer, e.g. its active relays
        LOG.trace("Update the unreachable peer to {} based on {}, ref {}", unreachablePeerAddress(), remotePeer,
            referrer);
        this.unreachablePeer = remotePeer;
        return true;
      }
    }

    return false;
  }

  public final Number160 relayPeerId() {
    return relayPeerId;
  }

  /**
   * Receive a message at the relay server from a given peer
   */
  @Override
  public final void handleResponse(Message message, PeerConnection peerConnection, boolean sign, final Responder responder)
      throws Exception {
    // TODO the sender should have the ip/port from the relay peer, the peerId
    // from the unreachable peer, in order to have 6 relays instead of 5
    handleResponse(message, responder);
  }

  /**
   * Receive a message at the relay server from a given peer
   */
  public final void handleResponse(Message message, final Responder responder) {
    // special treatment for ping and neighbor
    if (message.command() == RPC.Commands.PING.getNr()) {
      LOG.debug("Received message {} to handle ping for unreachable peer {}", message, unreachablePeer);
      handlePing(message, responder);
    } else if (message.command() == RPC.Commands.NEIGHBOR.getNr()) {
      LOG.debug("Received message {} to handle neighbor request for unreachable peer {}", message, unreachablePeer);
      handleNeigbhor(message, responder);
    } else {
      LOG.debug("Received message {} to forward to unreachable peer {}", message, unreachablePeer);
      FutureDone<Message> response = forwardToUnreachable(message);
      response.addListener(new BaseFutureAdapter<FutureDone<Message>>() {
        @Override
        public void operationComplete(FutureDone<Message> future) throws Exception {
          if (future.isSuccess()) {
            Message answerMessage = future.object();
            LOG.debug("Returing from relay to requester: {}", answerMessage);
            responder.response(answerMessage);
          } else {
            responder.failed(Type.DENIED, "Relaying message failed: " + future.failedReason());
          }
        }
      });
    }
  }

  /**
   * Forwards a message to the unrachable peer. The implementation should notify the unreachable peer
   * and return a response as soon as possible.
   *
   * @param message the message that is intended for the unreachable peer
   * @param sender the requester
   * @return the response to the requester
   */
  public abstract FutureDone<Message> forwardToUnreachable(Message message);

  /**
   * When a ping message is received
   *
   * @param message
   * @param responder
   * @param sender
   */
  private void handlePing(Message message, Responder responder) {
    Message response = createResponseMessage(message, isAlive() ? Type.OK : Type.EXCEPTION, unreachablePeerAddress());
    responder.response(response);
  }

  /**
   * Checks whether the relayed peer is still alive.
   *
   * @return
   */
  protected abstract boolean isAlive();

  /**
   * When a neighbor message is received
   *
   * @param message
   * @param responder
   * @param sender
   */
  private void handleNeigbhor(final Message message, Responder responder) {
    if (message.keyList().size() < 2) {
      throw new IllegalArgumentException("We need the location and domain key at least");
    }
    if (!(message.type() == Type.REQUEST_1 || message.type() == Type.REQUEST_2 || message.type() == Type.REQUEST_3 || message
        .type() == Type.REQUEST_4) && (message.command() == RPC.Commands.NEIGHBOR.getNr())) {
      throw new IllegalArgumentException("Message content is wrong");
    }
    Number160 locationKey = message.key(0);

    Collection<PeerAddress> neighbors = getNeighbors(locationKey, NeighborRPC.NEIGHBOR_SIZE);
    if (neighbors == null) {
      // return empty neighbor set
      Message response = createResponseMessage(message, Type.NOT_FOUND, unreachablePeer);
      response.neighborsSet(new NeighborSet(-1, Collections.<PeerAddress> emptyList()));
      responder.response(response);
      return;
    }

    // Create response message and set neighbors
    final Message responseMessage = createResponseMessage(message, Type.OK, unreachablePeer);

    // TODO: the relayed peer must be up-to-date here
    // neighbors.add(peerConnection.remotePeer());

    LOG.debug("found the following neighbors {}", neighbors);

    NeighborSet neighborSet = new NeighborSet(NeighborRPC.NEIGHBOR_LIMIT, neighbors);
    responseMessage.neighborsSet(neighborSet);

    // we can't do fast get here, as we only send over the neighbors and not the keys stored
    responder.response(responseMessage);
  }

  private SortedSet<PeerAddress> getNeighbors(Number160 id, int atLeast) {
    LOG.trace("Answering routing request on behalf of unreachable peer {}, neighbors of {}", unreachablePeerAddress(),
        id);
    if (peerMap == null) {
      return null;
    } else {
      return PeerMap.closePeers(unreachablePeerId(), id, NeighborRPC.NEIGHBOR_SIZE, peerMap);
    }
  }

  /**
   * Returns the current peer map from the mobile device
   */
  public final Collection<PeerAddress> getPeerMap() {
    Collection<PeerAddress> peerAddresses = new ArrayList<PeerAddress>();
    if (peerMap == null || peerMap.isEmpty()) {
      return peerAddresses;
    }

    Collection<PeerStatistic> statistics = new ArrayList<PeerStatistic>();
    for (Map<Number160, PeerStatistic> map : peerMap) {
      statistics.addAll(map.values());
    }
    for (PeerStatistic peerStatatistic : statistics) {
      peerAddresses.add(peerStatatistic.peerAddress());
    }
    return peerAddresses;
  }

  /**
   * Update the peerMap of the unreachable peer
   */
  public final void setPeerMap(List<Map<Number160, PeerStatistic>> peerMap) {
    this.peerMap = peerMap;
    peerMapUpdated();
  }

  /**
   * Is called when the unreachable peer sent an update to the relay peer
   */
  protected abstract void peerMapUpdated();
}
TOP

Related Classes of net.tomp2p.relay.BaseRelayForwarderRPC

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.