/* * Copyright 2012 Thomas Bocek * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package net.tomp2p.p2p; import io.netty.channel.ChannelHandler; import java.io.IOException; import java.security.KeyPair; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Timer; import net.tomp2p.connection2.Bindings; import net.tomp2p.connection2.ChannelClientConfiguration; import net.tomp2p.connection2.ChannelServerConficuration; import net.tomp2p.connection2.ConnectionBean; import net.tomp2p.connection2.DefaultSignatureFactory; import net.tomp2p.connection2.PeerBean; import net.tomp2p.connection2.PeerCreator; import net.tomp2p.connection2.PipelineFilter; import net.tomp2p.peers.Number160; import net.tomp2p.peers.PeerMap; import net.tomp2p.peers.PeerMapConfiguration; import net.tomp2p.peers.PeerStatusListener; import net.tomp2p.rpc.BloomfilterFactory; import net.tomp2p.rpc.BroadcastRPC; import net.tomp2p.rpc.DefaultBloomfilterFactory; import net.tomp2p.rpc.DirectDataRPC; import net.tomp2p.rpc.NeighborRPC; import net.tomp2p.rpc.PeerExchangeRPC; import net.tomp2p.rpc.PingRPC; import net.tomp2p.rpc.QuitRPC; import net.tomp2p.rpc.StorageRPC; //import net.tomp2p.rpc.TaskRPC; import net.tomp2p.rpc.TrackerRPC; import net.tomp2p.storage.IdentityManagement; import net.tomp2p.storage.StorageGeneric; import net.tomp2p.storage.StorageMemory; import net.tomp2p.storage.TrackerStorage; import net.tomp2p.utils.Utils; /** * The maker / builder of a {@link Peer} class. * * @author Thomas Bocek * */ public class PeerMaker { private static final KeyPair EMPTY_KEYPAIR = new KeyPair(null, null); // if the permits are chosen too high, then we might run into timeouts as we cant handle that many connections // withing the time limit private static final int MAX_PERMITS_PERMANENT_TCP = 250; private static final int MAX_PERMITS_UDP = 250; private static final int MAX_PERMITS_TCP = 250; // required private final Number160 peerId; // optional with reasonable defaults private KeyPair keyPair = null; private int p2pID = -1; private int tcpPort = -1; private int udpPort = -1; private Bindings bindings = null; private PeerMap peerMap = null; private Peer masterPeer = null; private ChannelServerConficuration channelServerConfiguration = null; private ChannelClientConfiguration channelClientConfiguration = null; private PeerStatusListener[] peerStatusListeners = null; private StorageGeneric storage = null; private TrackerStorage trackerStorage = null; private Boolean behindFirewall = null; // private int workerThreads = Runtime.getRuntime().availableProcessors() + 1; // private File fileMessageLogger = null; // private ConnectionConfiguration configuration = null; // private StorageGeneric storage; private BroadcastHandler broadcastHandler; private BloomfilterFactory bloomfilterFactory; private Timer timer = null; private MaintenanceTask maintenanceTask = null; private List<AutomaticFuture> automaticFutures = null; // private ReplicationExecutor replicationExecutor; // max, message size to transmit // private int maxMessageSize = 2 * 1024 * 1024; // PeerMap // private int bagSize = 2; // private int cacheTimeoutMillis = 60 * 1000; // private int maxNrBeforeExclude = 2; // private int[] waitingTimeBetweenNodeMaintenenceSeconds = { 5, 10, 20, 40, 80, 160 }; // private int cacheSize = 100; // enable / disable private boolean enableHandShakeRPC = true; private boolean enableStorageRPC = true; private boolean enableNeighborRPC = true; private boolean enableQuitRPC = true; private boolean enablePeerExchangeRPC = true; private boolean enableDirectDataRPC = true; private boolean enableTrackerRPC = true; private boolean enableTaskRPC = true; // P2P private boolean enableRouting = true; private boolean enableDHT = true; private boolean enableTracker = true; private boolean enableTask = true; private boolean enableMaintenance = true; private boolean enableIndirectReplication = false; private boolean enableBroadcast = true; // private Random rnd; /** * Creates a peermaker with the peer ID and an empty key pair. * * @param peerId * The peer Id */ public PeerMaker(final Number160 peerId) { this.peerId = peerId; } /** * Creates a peermaker with the key pair and generates out of this key pair the peer ID. * * @param keyPair * The public private key */ public PeerMaker(final KeyPair keyPair) { this.peerId = Utils.makeSHAHash(keyPair.getPublic().getEncoded()); this.keyPair = keyPair; } /** * Create a peer and start to listen for incoming connections. * * @return The peer that can operate in the P2P network. * @throws IOException . */ public Peer makeAndListen() throws IOException { if (behindFirewall == null) { behindFirewall = false; } if (channelServerConfiguration == null) { channelServerConfiguration = createDefaultChannelServerConfiguration(); } if (channelClientConfiguration == null) { channelClientConfiguration = createDefaultChannelClientConfiguration(); } if (keyPair == null) { keyPair = EMPTY_KEYPAIR; } if (p2pID == -1) { p2pID = 1; } if (tcpPort == -1) { tcpPort = Bindings.DEFAULT_PORT; } channelServerConfiguration.setTcpPort(tcpPort); if (udpPort == -1) { udpPort = Bindings.DEFAULT_PORT; } channelServerConfiguration.setUdpPort(tcpPort); if (bindings == null) { bindings = new Bindings(); } channelServerConfiguration.setBindings(bindings); if (peerMap == null) { peerMap = new PeerMap(new PeerMapConfiguration(peerId)); } if (storage == null) { storage = new StorageMemory(); } if (peerStatusListeners == null) { peerStatusListeners = new PeerStatusListener[] { peerMap }; } if (timer == null) { timer = new Timer(); } final PeerCreator peerCreator; if (masterPeer != null) { peerCreator = new PeerCreator(masterPeer.peerCreator(), peerId, keyPair); } else { peerCreator = new PeerCreator(p2pID, peerId, keyPair, channelServerConfiguration, channelClientConfiguration, peerStatusListeners, timer); } final Peer peer = new Peer(p2pID, peerId, peerCreator); PeerBean peerBean = peerCreator.peerBean(); peerBean.peerMap(peerMap); peerBean.keyPair(keyPair); peerBean.storage(storage); if (trackerStorage == null) { trackerStorage = new TrackerStorage(new IdentityManagement(peerBean.serverPeerAddress()), 300, peerBean.getReplicationTracker(), new Maintenance()); } peerBean.trackerStorage(trackerStorage); if (bloomfilterFactory == null) { peerBean.bloomfilterFactory(new DefaultBloomfilterFactory()); } if (broadcastHandler == null) { broadcastHandler = new DefaultBroadcastHandler(peer, new Random()); } ConnectionBean connectionBean = peerCreator.connectionBean(); // peerBean.setStorage(getStorage()); // Replication replicationStorage = new Replication(getStorage(), selfAddress, peerMap, 5); // peerBean.setReplicationStorage(replicationStorage); // TrackerStorage storageTracker = new TrackerStorage(identityManagement, // configuration.getTrackerTimoutSeconds(), peerBean, maintenance); // peerBean.setTrackerStorage(storageTracker); // Replication replicationTracker = new Replication(storageTracker, selfAddress, peerMap, 5); // peerBean.setReplicationTracker(replicationTracker); // peerMap.addPeerOfflineListener(storageTracker); // TaskManager taskManager = new TaskManager(connectionBean, workerThreads); // peerBean.setTaskManager(taskManager); // IdentityManagement identityManagement = new IdentityManagement(selfAddress); // Maintenance maintenance = new Maintenance(); initRPC(peer, connectionBean, peerBean); initP2P(peer, connectionBean, peerBean); if(maintenanceTask == null) { maintenanceTask = new MaintenanceTask(); } maintenanceTask.init(peer, timer); maintenanceTask.addMaintainable(peerMap); peerBean.maintenanceTask(maintenanceTask); if(automaticFutures!=null) { peer.setAutomaticFutures(automaticFutures); } return peer; } public ChannelServerConficuration createDefaultChannelServerConfiguration() { ChannelServerConficuration channelServerConfiguration = new ChannelServerConficuration(); channelServerConfiguration.setBindings(bindings); channelServerConfiguration.setTcpPort(tcpPort); channelServerConfiguration.setUdpPort(udpPort); channelServerConfiguration.setBehindFirewall(behindFirewall); channelServerConfiguration.pipelineFilter(new DefaultPipelineFilter()); channelServerConfiguration.signatureFactory(new DefaultSignatureFactory()); return channelServerConfiguration; } public ChannelClientConfiguration createDefaultChannelClientConfiguration() { ChannelClientConfiguration channelClientConfiguration = new ChannelClientConfiguration(); channelClientConfiguration.maxPermitsPermanentTCP(MAX_PERMITS_PERMANENT_TCP); channelClientConfiguration.maxPermitsTCP(MAX_PERMITS_TCP); channelClientConfiguration.maxPermitsUDP(MAX_PERMITS_UDP); channelClientConfiguration.pipelineFilter(new DefaultPipelineFilter()); channelClientConfiguration.signatureFactory(new DefaultSignatureFactory()); return channelClientConfiguration; } /** * Initialize the RPC communications. * * @param peer * The peer where the RPC reference is stored * @param connectionBean * The connection bean * @param peerBean * The peer bean */ private void initRPC(final Peer peer, final ConnectionBean connectionBean, final PeerBean peerBean) { // RPC communication if (isEnableHandShakeRPC()) { PingRPC handshakeRCP = new PingRPC(peerBean, connectionBean); peer.setHandshakeRPC(handshakeRCP); } if (isEnableStorageRPC()) { StorageRPC storageRPC = new StorageRPC(peerBean, connectionBean); peer.setStorageRPC(storageRPC); } if (isEnableNeighborRPC()) { NeighborRPC neighborRPC = new NeighborRPC(peerBean, connectionBean); peer.setNeighborRPC(neighborRPC); } if (isEnableDirectDataRPC()) { DirectDataRPC directDataRPC = new DirectDataRPC(peerBean, connectionBean); peer.setDirectDataRPC(directDataRPC); } if (isEnableQuitRPC()) { QuitRPC quitRCP = new QuitRPC(peerBean, connectionBean); peer.setQuitRPC(quitRCP); } if (isEnablePeerExchangeRPC()) { PeerExchangeRPC peerExchangeRPC = new PeerExchangeRPC(peerBean, connectionBean); peer.setPeerExchangeRPC(peerExchangeRPC); } if (isEnableDirectDataRPC()) { DirectDataRPC directDataRPC = new DirectDataRPC(peerBean, connectionBean); peer.setDirectDataRPC(directDataRPC); } if (isEnableTrackerRPC()) { TrackerRPC trackerRPC = new TrackerRPC(peerBean, connectionBean); peer.setTrackerRPC(trackerRPC); } if (isEnableBroadcast()) { BroadcastRPC broadcastRPC = new BroadcastRPC(peerBean, connectionBean, broadcastHandler); peer.setBroadcastRPC(broadcastRPC); } } private void initP2P(final Peer peer, final ConnectionBean connectionBean, final PeerBean peerBean) { // distributed communication if (isEnableRouting() && isEnableNeighborRPC()) { DistributedRouting routing = new DistributedRouting(peerBean, peer.getNeighborRPC()); peer.setDistributedRouting(routing); } if (isEnableRouting() && isEnableStorageRPC() && isEnableDirectDataRPC()) { DistributedHashTable dht = new DistributedHashTable(peer.getDistributedRouting(), peer.getStoreRPC(), peer.getDirectDataRPC(), peer.getQuitRPC()); peer.setDistributedHashMap(dht); } /*if (isEnableRouting() && isEnableTrackerRPC() && * isEnablePeerExchangeRPC()) { DistributedTracker tracker = new DistributedTracker(peerBean, * peer.getDistributedRouting(), peer.getTrackerRPC(), peer.getPeerExchangeRPC()); * peer.setDistributedTracker(tracker); } if (isEnableTaskRPC() && isEnableTask() && isEnableRouting()) { // the * task manager needs to use the rpc to send the result back. //TODO: enable again * //peerBean.getTaskManager().init(peer.getTaskRPC()); //AsyncTask asyncTask = new AsyncTask(peer.getTaskRPC(), * connectionBean.getScheduler(), peerBean); //peer.setAsyncTask(asyncTask); * //peerBean.getTaskManager().addListener(asyncTask); * //connectionBean.getScheduler().startTracking(peer.getTaskRPC(), // * connectionBean.getConnectionReservation()); //DistributedTask distributedTask = new * DistributedTask(peer.getDistributedRouting(), peer.getAsyncTask()); * //peer.setDistributedTask(distributedTask); } // maintenance if (isEnableMaintenance()) { //TODO: enable * again //connectionHandler // .getConnectionBean() // .getScheduler() // * .startMaintainance(peerBean.getPeerMap(), peer.getHandshakeRPC(), // * connectionBean.getConnectionReservation(), 5); } // indirect replication //TODO: enable again //if * (isEnableIndirectReplication() && isEnableStorageRPC()) { // if (replicationExecutor == null) { // * replicationExecutor = new ReplicationExecutor(peer); // } // peer.getScheduledFutures().add( // * connectionBean // .getScheduler() // .getScheduledExecutorServiceReplication() // * .scheduleWithFixedDelay(replicationExecutor, replicationRefreshMillis, // replicationRefreshMillis, * TimeUnit.MILLISECONDS)); //} */ } public Number160 peerId() { return peerId; } public KeyPair keyPair() { return keyPair; } public PeerMaker keyPair(KeyPair keyPair) { this.keyPair = keyPair; return this; } public int p2pId() { return p2pID; } public PeerMaker p2pId(int p2pID) { this.p2pID = p2pID; return this; } public int tcpPort() { return tcpPort; } public PeerMaker tcpPort(int tcpPort) { this.tcpPort = tcpPort; return this; } public int udpPort() { return udpPort; } public PeerMaker udpPort(int udpPort) { this.udpPort = udpPort; return this; } public PeerMaker ports(int port) { this.udpPort = port; this.tcpPort = port; return this; } public Bindings bindings() { return bindings; } public PeerMaker bindings(Bindings bindings) { this.bindings = bindings; return this; } public PeerMap peerMap() { return peerMap; } public PeerMaker peerMap(PeerMap peerMap) { this.peerMap = peerMap; return this; } public Peer masterPeer() { return masterPeer; } public PeerMaker masterPeer(Peer masterPeer) { this.masterPeer = masterPeer; return this; } public ChannelServerConficuration channelServerConfiguration() { return channelServerConfiguration; } public PeerMaker channelServerConfiguration(ChannelServerConficuration channelServerConfiguration) { this.channelServerConfiguration = channelServerConfiguration; return this; } public ChannelClientConfiguration channelClientConfiguration() { return channelClientConfiguration; } public PeerMaker channelClientConfiguration(ChannelClientConfiguration channelClientConfiguration) { this.channelClientConfiguration = channelClientConfiguration; return this; } public PeerStatusListener[] peerStatusListeners() { return peerStatusListeners; } public PeerMaker peerStatusListeners(PeerStatusListener[] peerStatusListeners) { this.peerStatusListeners = peerStatusListeners; return this; } public BroadcastHandler broadcastHandler() { return broadcastHandler; } public PeerMaker broadcastHandler(BroadcastHandler broadcastHandler) { this.broadcastHandler = broadcastHandler; return this; } public BloomfilterFactory bloomfilterFactory() { return bloomfilterFactory; } public PeerMaker bloomfilterFactory(BloomfilterFactory bloomfilterFactory) { this.bloomfilterFactory = bloomfilterFactory; return this; } public boolean isEnableHandShakeRPC() { return enableHandShakeRPC; } public PeerMaker setEnableHandShakeRPC(boolean enableHandShakeRPC) { this.enableHandShakeRPC = enableHandShakeRPC; return this; } public boolean isEnableStorageRPC() { return enableStorageRPC; } public PeerMaker setEnableStorageRPC(boolean enableStorageRPC) { this.enableStorageRPC = enableStorageRPC; return this; } public boolean isEnableNeighborRPC() { return enableNeighborRPC; } public PeerMaker setEnableNeighborRPC(boolean enableNeighborRPC) { this.enableNeighborRPC = enableNeighborRPC; return this; } public boolean isEnableQuitRPC() { return enableQuitRPC; } public PeerMaker setEnableQuitRPC(boolean enableQuitRPC) { this.enableQuitRPC = enableQuitRPC; return this; } public boolean isEnablePeerExchangeRPC() { return enablePeerExchangeRPC; } public PeerMaker setEnablePeerExchangeRPC(boolean enablePeerExchangeRPC) { this.enablePeerExchangeRPC = enablePeerExchangeRPC; return this; } public boolean isEnableDirectDataRPC() { return enableDirectDataRPC; } public PeerMaker setEnableDirectDataRPC(boolean enableDirectDataRPC) { this.enableDirectDataRPC = enableDirectDataRPC; return this; } public boolean isEnableTrackerRPC() { return enableTrackerRPC; } public PeerMaker setEnableTrackerRPC(boolean enableTrackerRPC) { this.enableTrackerRPC = enableTrackerRPC; return this; } public boolean isEnableTaskRPC() { return enableTaskRPC; } public PeerMaker setEnableTaskRPC(boolean enableTaskRPC) { this.enableTaskRPC = enableTaskRPC; return this; } public boolean isEnableRouting() { return enableRouting; } public PeerMaker setEnableRouting(boolean enableRouting) { this.enableRouting = enableRouting; return this; } public boolean isEnableDHT() { return enableDHT; } public PeerMaker setEnableDHT(boolean enableDHT) { this.enableDHT = enableDHT; return this; } public boolean isEnableTracker() { return enableTracker; } public PeerMaker setEnableTracker(boolean enableTracker) { this.enableTracker = enableTracker; return this; } public boolean isEnableTask() { return enableTask; } public PeerMaker setEnableTask(boolean enableTask) { this.enableTask = enableTask; return this; } public boolean isEnableMaintenance() { return enableMaintenance; } public PeerMaker setEnableMaintenance(boolean enableMaintenance) { this.enableMaintenance = enableMaintenance; return this; } public boolean isEnableIndirectReplication() { return enableIndirectReplication; } public PeerMaker setEnableIndirectReplication(boolean enableIndirectReplication) { this.enableIndirectReplication = enableIndirectReplication; return this; } public boolean isEnableBroadcast() { return enableBroadcast; } public PeerMaker setEnableBroadcast(boolean enableBroadcast) { this.enableBroadcast = enableBroadcast; return this; } /** * @return True if this peer is behind a firewall and cannot be accessed directly */ public boolean isBehindFirewall() { return behindFirewall == null?false:behindFirewall; } /** * @param behindFirewall * Set to true if this peer is behind a firewall and cannot be accessed directly * @return This class */ public PeerMaker setBehindFirewall(final boolean behindFirewall) { this.behindFirewall = behindFirewall; return this; } /** * Set peer to be behind a firewall and cannot be accessed directly. * * @return This class */ public PeerMaker setBehindFirewall() { this.behindFirewall = true; return this; } public PeerMaker addAutomaticFuture(AutomaticFuture automaticFuture) { if(automaticFutures==null) { automaticFutures = new ArrayList<>(1); } automaticFutures.add(automaticFuture); return this; } /** * The default filter is no filter, just return the same array. * * @author Thomas Bocek * */ private static class DefaultPipelineFilter implements PipelineFilter { @Override public void filter(final Map<String, ChannelHandler> channelHandlers, final boolean tcp, final boolean client) { } } }