package se.chalmers.gdcn.network; import se.chalmers.gdcn.communicationToUI.CommandWord; import se.chalmers.gdcn.communicationToUI.NetworkInterface; import se.chalmers.gdcn.communicationToUI.Operation; import se.chalmers.gdcn.communicationToUI.OperationFinishedListener; import se.chalmers.gdcn.files.DeceitfulFileUtils; import se.chalmers.gdcn.hashcash.Challenge; import se.chalmers.gdcn.hashcash.Solution; import net.tomp2p.p2p.Peer; import net.tomp2p.peers.Number160; import net.tomp2p.peers.PeerAddress; import net.tomp2p.storage.Data; import se.chalmers.gdcn.replica.ReplicaBox; import se.chalmers.gdcn.replica.ReplicaManager.ReplicaID; import java.io.Serializable; import java.util.Map; import java.util.Random; import java.util.concurrent.ExecutorService; /** * Created by Leif on 2014-03-29. * * Only ONE Passer object may be created for each peer! Handles all messages to and from this Peer. */ public class TaskPasserDeny extends Passer { private final NetworkInterface client; private final WorkerID myWorkerID; private final Map<String, byte[]> falseResults; private final ExecutorService pool; private static final Random random = new Random(); /** * Message passer for sending messages regarding tasks. OBS! Only ONE Passer may be present for a Peer. * * @param peer This peer * @param client Client to put and get results * @param falseResults * @param pool */ public TaskPasserDeny(Peer peer, NetworkInterface client, Map<String, byte[]> falseResults, ExecutorService pool) { super(peer); this.falseResults = falseResults; this.pool = pool; this.myWorkerID = new WorkerID(peer.getPeerBean().getKeyPair().getPublic()); this.client = client; } /** * Starts task process working for this peer * * Works concurrently to solve challenges! * @param jobOwner Peer to work for */ public void requestWork(final PeerAddress jobOwner){ System.out.println("Request work from " + Passer.print(jobOwner)); sendRequest(jobOwner, new TaskMessage(TaskMessageType.REQUEST_CHALLENGE, myWorkerID, ""), new OnReplyCommand() { @Override public void execute(Object replyMessageContent) { TaskMessage taskMessage = TaskMessage.check(replyMessageContent); if (taskMessage.getType() != TaskMessageType.CHALLENGE) { throw new IllegalStateException("Should be a Challenge response here!"); } final Challenge challenge = (Challenge) taskMessage.getActualContent(); System.out.println("Challenge received: "+challenge.toString()); Runnable solver = new Runnable() { @Override public void run() { Solution challengeSolution = challenge.solve(); System.out.println("Challenge solved"); sendRequest(jobOwner, new TaskMessage(TaskMessageType.REQUEST_TASK, myWorkerID, challengeSolution), new OnReplyCommand() { @Override public void execute(Object replyMessageContent2) { TaskMessage taskMessage2 = TaskMessage.check(replyMessageContent2); switch (taskMessage2.getType()) { case TASK: ReplicaBox replicaBox = (ReplicaBox) taskMessage2.getActualContent(); System.out.println("Start processing task, \n\tResultKey: "+replicaBox.getResultKey()); workOnTaskDeceitfully(jobOwner, replicaBox); System.out.println("Some Task was received from " + Passer.print(jobOwner)); break; case NO_TASK_AVAILABLE: System.out.println("No task available form this job owner any more"); //TODO break; case CHALLENGE_FAIL: throw new IllegalStateException("Solution failed: " + taskMessage2.getActualContent()); default: throw new IllegalStateException("Should be a Challenge response here!"); } } }); } }; pool.submit(solver); } }); } /** * Works on this task until finished. * Sybil method! * * @param jobOwner Peer to send result to * @param replicaBox Task (replica) to work on */ private void workOnTaskDeceitfully(final PeerAddress jobOwner, final ReplicaBox replicaBox){ final Number160 resultKey = replicaBox.getResultKey(); final ReplicaID replicaID = replicaBox.getReplicaID(); System.out.println("Task " + replicaID + " finished. Attempt to upload and notify job owner."); client.addListener(new OperationFinishedListener(client, resultKey, CommandWord.PUT) { @Override protected void operationFinished(Operation operation) { if(operation.isSuccess()){ System.out.println("Task "+replicaID+" finished. Job owner notified if still online."); sendNoReplyMessage(jobOwner, new TaskMessage(TaskMessageType.RESULT_UPLOADED, myWorkerID, replicaBox.getReplicaID())); } else { // } } }); byte[] result = null; //Uses ConcurrentHashMap so this synchronization is actually not needed? synchronized (falseResults) { final String realTask = DeceitfulFileUtils.deduceTask(replicaBox.getTaskMeta()); result = falseResults.get(realTask); if(result == null){ result = generateFalseResult(); falseResults.put(realTask, result); } } client.put(resultKey, new Data(result)); System.out.println("Answer to "+replicaID+" got "+result.length+" bytes"); } private static byte[] generateFalseResult(){ byte[] result = new byte[100+random.nextInt(300)]; random.nextBytes(result); return result; } /** * {@inheritDoc} */ @Override synchronized protected Serializable handleRequest(PeerAddress sender, Object messageContent) { TaskMessage taskMessage = TaskMessage.check(messageContent); WorkerID workerID = taskMessage.getSenderID(); return null; } /** * {@inheritDoc} */ @Override synchronized protected void handleNoReply(PeerAddress sender, Object messageContent) { TaskMessage taskMessage = TaskMessage.check(messageContent); } }