Package net.tomp2p.message

Source Code of net.tomp2p.message.Encoder

package net.tomp2p.message;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.PublicKey;
import java.security.SignatureException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import net.tomp2p.connection.SignatureFactory;
import net.tomp2p.message.Message.Content;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.Number640;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.peers.PeerSocketAddress;
import net.tomp2p.peers.PeerStatistic;
import net.tomp2p.rpc.SimpleBloomFilter;
import net.tomp2p.storage.AlternativeCompositeByteBuf;
import net.tomp2p.storage.Data;

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

public class Encoder {

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

    private boolean header = false;
    private boolean resume = false;
    private Message message;

    private final SignatureFactory signatureFactory;

    public Encoder(SignatureFactory signatureFactory) {
        this.signatureFactory = signatureFactory;
    }

    public boolean write(final AlternativeCompositeByteBuf buf, final Message message, SignatureCodec signatureCodec) throws InvalidKeyException,
            SignatureException, IOException {

        this.message = message;
        LOG.debug("message for outbound {}", message);
       
        if (message.sender().isRelayed() && message.peerSocketAddresses().isEmpty()) {
          message.peerSocketAddresses(message.sender().peerSocketAddresses());
        }

        if (!header) {
            MessageHeaderCodec.encodeHeader(buf, message);
            header = true;
        } else {
            LOG.debug("send a follow-up message {}", message);
            resume = true;
        }

        boolean done = loop(buf);
        LOG.debug("message encoded {}", message);

        // write out what we have
        if (buf.isReadable() && done) {

            // check if we need to sign the message
            if (message.isSign()) {
              //we sign if we did not provide a signature already
              if(signatureCodec == null) {
                signatureCodec = signatureFactory.sign(message.privateKey(), buf);
              }
              //in case of relay, we have a signature, so we need to reuse this
              signatureCodec.write(buf);
            }
        }
        return done;
    }

    private boolean loop(AlternativeCompositeByteBuf buf) throws InvalidKeyException, SignatureException, IOException {
        MessageContentIndex next;
        while ((next = message.contentReferences().peek()) != null) {
          final int start = buf.writerIndex();
          final Content content = next.content();
            switch (content) {
            case KEY:
                buf.writeBytes(message.key(next.index()).toByteArray());
                message.contentReferences().poll();
                break;
            case INTEGER:
                buf.writeInt(message.intAt(next.index()));
                message.contentReferences().poll();
                break;
            case LONG:
                buf.writeLong(message.longAt(next.index()));
                message.contentReferences().poll();
                break;
            case SET_NEIGHBORS:
                NeighborSet neighborSet = message.neighborsSet(next.index());
                // length
                buf.writeByte(neighborSet.size());
                for (PeerAddress neighbor : neighborSet.neighbors()) {
                    buf.writeBytes(neighbor.toByteArray());
                }
                message.contentReferences().poll();
                break;
            case SET_PEER_SOCKET:
                List<PeerSocketAddress> list = message.peerSocketAddresses();
                // length
                buf.writeByte(list.size());
                for (PeerSocketAddress psa : list) {
                  // IP version flag
                  buf.writeByte(psa.isIPv4() ? 0:1);
                    buf.writeBytes(psa.toByteArray());
                }
                message.contentReferences().poll();
                break;
            case BLOOM_FILTER:
                SimpleBloomFilter<Number160> simpleBloomFilter = message.bloomFilter(next.index());
                simpleBloomFilter.toByteBuf(buf);
                message.contentReferences().poll();
                break;
            case SET_KEY640:
                KeyCollection keys = message.keyCollection(next.index());
                // length
                buf.writeInt(keys.size());
                if (keys.isConvert()) {
                    for (Number160 key : keys.keysConvert()) {
                        buf.writeBytes(keys.locationKey().toByteArray());
                        buf.writeBytes(keys.domainKey().toByteArray());
                        buf.writeBytes(key.toByteArray());
                        buf.writeBytes(keys.versionKey().toByteArray());
                    }
                } else {
                    for (Number640 key : keys.keys()) {
                        buf.writeBytes(key.locationKey().toByteArray());
                        buf.writeBytes(key.domainKey().toByteArray());
                        buf.writeBytes(key.contentKey().toByteArray());
                        buf.writeBytes(key.versionKey().toByteArray());
                    }
                }
                message.contentReferences().poll();
                break;
            case MAP_KEY640_DATA:
                DataMap dataMap = message.dataMap(next.index());
                // legnth
                buf.writeInt(dataMap.size());
                if (dataMap.isConvert()) {
                    for (Entry<Number160, Data> entry : dataMap.dataMapConvert().entrySet()) {
                      buf.writeBytes(dataMap.locationKey().toByteArray());
                        buf.writeBytes(dataMap.domainKey().toByteArray());
                        buf.writeBytes(entry.getKey().toByteArray());
                        buf.writeBytes(dataMap.versionKey().toByteArray());
                        encodeData(buf, entry.getValue(), dataMap.isConvertMeta(), !message.isRequest());
                    }
                } else {
                    for (Entry<Number640, Data> entry : dataMap.dataMap().entrySet()) {
                        buf.writeBytes(entry.getKey().locationKey().toByteArray());
                        buf.writeBytes(entry.getKey().domainKey().toByteArray());
                        buf.writeBytes(entry.getKey().contentKey().toByteArray());
                        buf.writeBytes(entry.getKey().versionKey().toByteArray());
                        encodeData(buf, entry.getValue(), dataMap.isConvertMeta(), !message.isRequest());
                    }
                }
                message.contentReferences().poll();
                break;
            case MAP_KEY640_KEYS:
                KeyMap640Keys keyMap640Keys = message.keyMap640Keys(next.index());
                // length
                buf.writeInt(keyMap640Keys.size());
                for (Entry<Number640, Collection<Number160>> entry : keyMap640Keys.keysMap().entrySet()) {
                    buf.writeBytes(entry.getKey().locationKey().toByteArray());
                    buf.writeBytes(entry.getKey().domainKey().toByteArray());
                    buf.writeBytes(entry.getKey().contentKey().toByteArray());
                    buf.writeBytes(entry.getKey().versionKey().toByteArray());
                    // write number of based-on keys
                    buf.writeByte(entry.getValue().size());
                    // write based-on keys
                    for (Number160 basedOnKey : entry.getValue()) {
                        buf.writeBytes(basedOnKey.toByteArray());
                    }
                }
                message.contentReferences().poll();
                break;
            case MAP_KEY640_BYTE:
                KeyMapByte keysMap = message.keyMapByte(next.index());
                // length
                buf.writeInt(keysMap.size());
                for (Entry<Number640, Byte> entry : keysMap.keysMap().entrySet()) {
                    buf.writeBytes(entry.getKey().locationKey().toByteArray());
                    buf.writeBytes(entry.getKey().domainKey().toByteArray());
                    buf.writeBytes(entry.getKey().contentKey().toByteArray());
                    buf.writeBytes(entry.getKey().versionKey().toByteArray());
                    buf.writeByte(entry.getValue());
                }
                message.contentReferences().poll();
                break;
            case BYTE_BUFFER:
                Buffer buffer = message.buffer(next.index());
                if (!resume) {
                    buf.writeInt(buffer.length());
                }
                // length
                int readable = buffer.readable();
                buf.writeBytes(buffer.buffer(), readable);
                if (buffer.incRead(readable) == buffer.length()) {
                    message.contentReferences().poll();
                } else if (message.isStreaming()) {
                    LOG.debug("Partial message of lengt {} sent.", readable);
                    return false;
                } else {
                  final String description = "Larger buffer has been announced, but not in message streaming mode. This is wrong.";
                    LOG.error(description);
                    throw new RuntimeException(description);
                }
                break;
            case SET_TRACKER_DATA:
                TrackerData trackerData = message.trackerData(next.index());
                buf.writeByte(trackerData.peerAddresses().size()); // 1 bytes - length, max. 255
                for (Map.Entry<PeerStatistic, Data> entry : trackerData.peerAddresses().entrySet()) {
                  byte[] me = entry.getKey().peerAddress().toByteArray();
                    buf.writeBytes(me);
                    Data data = entry.getValue().duplicate();
                    encodeData(buf, data, false, !message.isRequest());
                }
                message.contentReferences().poll();
                break;
            case PUBLIC_KEY_SIGNATURE:
                // flag to encode public key
                message.setHintSign();
                // then do the regular public key stuff -> no break
            case PUBLIC_KEY:
              PublicKey publicKey = message.publicKey(next.index());
              signatureFactory.encodePublicKey(publicKey, buf);
              message.contentReferences().poll();
              break;
            default:
                throw new RuntimeException("Unknown type: " + next.content());
            }
            LOG.debug("wrote in encoder for {} {}", content, buf.writerIndex() - start);

        }
        return true;
    }

  private void encodeData(AlternativeCompositeByteBuf buf, Data data, boolean isConvertMeta, boolean isReply) throws InvalidKeyException, SignatureException, IOException {
    if(isConvertMeta) {
      data = data.duplicateMeta();
    } else {
      data = data.duplicate();
    }
    if(isReply) {
      int ttl = (int) ((data.expirationMillis() - System.currentTimeMillis()) / 1000);
      data.ttlSeconds(ttl < 0 ? 0 : ttl);
    }
    final int startWriter = buf.writerIndex();
      data.encodeHeader(buf, signatureFactory);
      data.encodeBuffer(buf);
      data.encodeDone(buf, signatureFactory, message.privateKey());
    }

    public Message message() {
        return message;
    }

    public void reset() {
        header = false;
        resume = false;
    }
}
TOP

Related Classes of net.tomp2p.message.Encoder

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.