Package net.tomp2p.relay

Source Code of net.tomp2p.relay.RelayUtils

package net.tomp2p.relay;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import net.tomp2p.connection.ConnectionBean;
import net.tomp2p.connection.ConnectionConfiguration;
import net.tomp2p.connection.PeerBean;
import net.tomp2p.connection.PeerConnection;
import net.tomp2p.connection.RequestHandler;
import net.tomp2p.connection.SignatureFactory;
import net.tomp2p.futures.BaseFutureAdapter;
import net.tomp2p.futures.FutureChannelCreator;
import net.tomp2p.futures.FuturePeerConnection;
import net.tomp2p.futures.FutureResponse;
import net.tomp2p.message.Buffer;
import net.tomp2p.message.Decoder;
import net.tomp2p.message.Encoder;
import net.tomp2p.message.Message;
import net.tomp2p.p2p.Peer;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.peers.PeerMap;
import net.tomp2p.peers.PeerMapConfiguration;
import net.tomp2p.peers.PeerStatistic;
import net.tomp2p.relay.android.MessageBuffer;
import net.tomp2p.storage.AlternativeCompositeByteBuf;

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

public class RelayUtils {

  private static final Logger LOG = LoggerFactory.getLogger(RelayUtils.class);
  private static Charset charset = Charset.forName("UTF-8");
  private static CharsetEncoder encoder = charset.newEncoder();
  private static CharsetDecoder decoder = charset.newDecoder();
 
  private RelayUtils() {
    // only static methods
  }

  public static List<Map<Number160, PeerStatistic>> unflatten(Collection<PeerAddress> map, PeerAddress sender) {
    PeerMapConfiguration peerMapConfiguration = new PeerMapConfiguration(sender.peerId());
    PeerMap peerMap = new PeerMap(peerMapConfiguration);
    for (PeerAddress peerAddress : map) {
      peerMap.peerFound(peerAddress, null, null);
    }
    return peerMap.peerMapVerified();
  }

  public static Collection<PeerAddress> flatten(List<Map<Number160, PeerStatistic>> maps) {
    Collection<PeerAddress> result = new ArrayList<PeerAddress>();
    for (Map<Number160, PeerStatistic> map : maps) {
      for (PeerStatistic peerStatatistic : map.values()) {
        result.add(peerStatatistic.peerAddress());
      }
    }
    return result;
  }

  /**
   * Basically does the same as
   * {@link MessageUtils#decodeMessage(Buffer, InetSocketAddress, InetSocketAddress, SignatureFactory)}, but
   * in addition checks that the relay peers of the decoded message are set correctly
   */
  public static Message decodeRelayedMessage(Buffer buf, InetSocketAddress recipient, InetSocketAddress sender,
      SignatureFactory signatureFactory) throws InvalidKeyException, NoSuchAlgorithmException,
      InvalidKeySpecException, SignatureException, IOException {
    Message decodedMessage = decodeMessage(buf, recipient, sender, signatureFactory);
    boolean isRelay = decodedMessage.sender().isRelayed();
    if (isRelay && !decodedMessage.peerSocketAddresses().isEmpty()) {
      PeerAddress tmpSender = decodedMessage.sender().changePeerSocketAddresses(decodedMessage.peerSocketAddresses());
      decodedMessage.sender(tmpSender);
    }
    return decodedMessage;
  }
 
  /**
   * Composes all messages of a list into a single buffer object, ready to be transmitted over the network.
   * The composing happens in-order. Alternatively, the message size and then the message is written to the
   * buffer. Use {@link MessageBuffer#decomposeCompositeBuffer(ByteBuf)} to disassemble.
   *
   * @param messages the messages to compose
   * @param signatureFactory the signature factory, necessary for encoding the messages
   * @return a single buffer holding all messages of the list
   */
  public static ByteBuf composeMessageBuffer(List<Message> messages, SignatureFactory signatureFactory) {
    ByteBuf buffer = Unpooled.buffer();
    for (Message msg : messages) {
      try {
        msg.restoreContentReferences();
        msg.restoreBuffers();
        Buffer encoded = encodeMessage(msg, signatureFactory);

        buffer.writeInt(encoded.length());
        buffer.writeBytes(encoded.buffer());
      } catch (Exception e) {
        LOG.error("Cannot encode the buffered message. Skip it.", e);
      }
    }
    return buffer;
  }

  /**
   * Decomposes a buffer containing multiple buffers into an (ordered) list of small buffers. Alternating,
   * the size of the message and the message itself are encoded in the message buffer. First, the size is
   * read, then k bytes are read from the buffer (the message). Then again, the size of the next messages is
   * determined.
   *
   * @param messageBuffer the message buffer
   * @return a list of buffers
   */
  public static List<Message> decomposeCompositeBuffer(ByteBuf messageBuffer, InetSocketAddress recipient, InetSocketAddress sender,
      SignatureFactory signatureFactory) {
    List<Message> messages = new ArrayList<Message>();
    while (messageBuffer.readableBytes() > 0) {
      int size = messageBuffer.readInt();
      ByteBuf message = messageBuffer.readBytes(size);
     
      try {
        Message decodedMessage = decodeRelayedMessage(new Buffer(message), recipient, sender, signatureFactory);
        messages.add(decodedMessage);
      } catch (Exception e) {
        LOG.error("Cannot decode buffered message. Skip it.", e);
      }
    }

    return messages;
  }
 
  /**
   * Encodes a message into a buffer, such that it can be used as a message payload (piggybacked), stored, etc.
   */
  public static Buffer encodeMessage(Message message, SignatureFactory signatureFactory) throws InvalidKeyException, SignatureException, IOException {
    Encoder e = new Encoder(signatureFactory);
    AlternativeCompositeByteBuf buf = AlternativeCompositeByteBuf.compBuffer();
    e.write(buf, message, message.receivedSignature());
    return new Buffer(buf);
  }

  /**
   * Decodes a message which was encoded using {{@link #encodeMessage(Message, SignatureFactory)}}.
   */
  public static Message decodeMessage(Buffer buf, InetSocketAddress recipient, InetSocketAddress sender, SignatureFactory signatureFactory)
          throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, SignatureException, IOException {
    Decoder d = new Decoder(signatureFactory);
    final int readerBefore = buf.buffer().readerIndex();
    d.decodeHeader(buf.buffer(), recipient, sender);
    final boolean donePayload = d.decodePayload(buf.buffer());
    d.decodeSignature(buf.buffer(), readerBefore, donePayload);
    return d.message();
  }
 
  /**
   * Calculates the size of the message
   */
  public static int getMessageSize(Message message, SignatureFactory signatureFactory) throws InvalidKeyException, SignatureException, IOException {
    // TODO instead of real encoding, calculate it using the content references
    int size = encodeMessage(message, signatureFactory).length();
    message.restoreContentReferences();
    message.restoreBuffers();
    return size;
  }

  /**
   * Encodes any String into a buffer to send it with a message
   *
   * @param content the String to encode into a buffer
   * @return a buffer containing the (encoded) String.
   */
  public static Buffer encodeString(String content) {
    if (content == null) {
      return null;
    }

    ByteBuffer byteBuffer;
    synchronized (encoder) {
      encoder.reset();
      try {
        byteBuffer = encoder.encode(CharBuffer.wrap(content));
      } catch (CharacterCodingException e) {
        return null;
      }
      encoder.flush(byteBuffer);
    }
    ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(byteBuffer);
    return new Buffer(wrappedBuffer);
  }

  /**
   * Decodes buffer containing a String
   *
   * @param buffer the buffer received in a message
   * @return the encodeed String
   */
  public static String decodeString(Buffer buffer) {
    if (buffer == null || buffer.buffer() == null) {
      return null;
    }

    ByteBuffer nioBuffer = buffer.buffer().nioBuffer();
    synchronized (decoder) {
      decoder.reset();
      CharBuffer decoded;
      try {
        decoded = decoder.decode(nioBuffer);
      } catch (CharacterCodingException e) {
        return null;
      }
      decoder.flush(decoded);
      return decoded.toString();
    }
  }
 
  /**
   * Send a Message from one Peer to another Peer internally. This avoids the
   * overhead of sendDirect.
   */
  private static void send(final PeerConnection peerConnection, PeerBean peerBean, ConnectionBean connectionBean, ConnectionConfiguration config, final FutureResponse futureResponse) {
    final RequestHandler<FutureResponse> requestHandler = new RequestHandler<FutureResponse>(futureResponse, peerBean, connectionBean, config);
    final FutureChannelCreator fcc = peerConnection.acquire(futureResponse);
    fcc.addListener(new BaseFutureAdapter<FutureChannelCreator>() {
      @Override
      public void operationComplete(FutureChannelCreator future) throws Exception {
        if (future.isSuccess()) {
          requestHandler.sendTCP(peerConnection.channelCreator(), peerConnection);
        } else {
          futureResponse.failed(future);
        }
      }
    });
  }

  /**
   * Send a Message from one Peer to another Peer internally. This avoids the
   * overhead of sendDirect. This Method is used for relaying and reverse
   * Connection setup.
   * @return the response
   */
  public static FutureResponse send(final PeerConnection peerConnection, PeerBean peerBean, ConnectionBean connectionBean, ConnectionConfiguration config, Message message) {
    final FutureResponse futureResponse = new FutureResponse(message);
    send(peerConnection, peerBean, connectionBean, config, futureResponse);
    return futureResponse;
  }
 
  /**
   * Opens a new peer connection to the receiver and sends the message through it.
   * @param peer
   * @param message
   * @param config
   * @return
   */
  public static FutureResponse connectAndSend(final Peer peer, final Message message, final ConnectionConfiguration config) {
    final FutureResponse futureResponse = new FutureResponse(message);
    final FuturePeerConnection fpc = peer.createPeerConnection(message.recipient());
    fpc.addListener(new BaseFutureAdapter<FuturePeerConnection>() {
            public void operationComplete(final FuturePeerConnection futurePeerConnection) throws Exception {
                if (futurePeerConnection.isSuccess()) {
                  // successfully created a connection to the other peer
                  final PeerConnection peerConnection = futurePeerConnection.object();
                 
                  // send the message
                  send(peerConnection, peer.peerBean(), peer.connectionBean(), config, futureResponse);
                } else {
                    futureResponse.failed(fpc);
                }
            }
        });
   
    return futureResponse;
  }
}
TOP

Related Classes of net.tomp2p.relay.RelayUtils

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.