/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.redPandaLib.core; import org.redPandaLib.services.MessageDownloader; import java.util.Map.Entry; import java.util.Set; import org.redPandaLib.core.messages.RawMsg; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; import org.redPandaLib.Main; import org.redPandaLib.crypt.ECKey; import org.redPandaLib.crypt.RC4; /** * * @author rflohr */ public class Peer implements Comparable<Peer> { public String ip; public int port; public int connectAble = 0; public int retries = 0; long lastRetryAfter5 = 0; public long lastActionOnConnection = 0; int cnt = 0; public long connectedSince = 0; long lastAllMsgsQuerried = Settings.till; public long nonce; private ArrayList<String> filterAdresses; private SocketChannel socketChannel; // public ArrayList<ByteBuffer> readBuffers = new ArrayList<ByteBuffer>(); // public ArrayList<ByteBuffer> writeBuffers = new ArrayList<ByteBuffer>(); public ByteBuffer readBuffer; public ByteBuffer writeBuffer; SelectionKey selectionKey; public boolean firstCommandsProceeded; private boolean connected = false; public boolean isConnecting; public long lastPinged = 0; public double ping = 0; public int requestedMsgs = 0; public PeerTrustData peerTrustData; byte[] toEncodeForAuthFromMe; byte[] toEncodeForAuthFromHim; boolean requestedNewAuth; public boolean authed = false; RC4 writeKey; RC4 readKey; public ByteBuffer writeBufferCrypted; public ByteBuffer readBufferCrypted; public int trustRetries = 0; public final ReentrantLock writeBufferLock = new ReentrantLock(); public Thread connectinThread; public int parsedCryptedBytes = 0; public long syncMessagesSince = 0; public ArrayList<Integer> removedSendMessages = new ArrayList<Integer>(); public int maxSimultaneousRequests = 1; public ArrayList<Integer> myInterestedChannelsCodedInHisIDs = new ArrayList<Integer>(); //for perfomance, so I dont have to look in the database for every message i am introduced. public long sendBytes = 0; public long receivedBytes = 0; public Peer(String ip, int port) { this.ip = ip; this.port = port; } public boolean equalsIpAndPort(Object obj) { if (obj instanceof Peer) { Peer n2 = (Peer) obj; return (ip.equals(n2.ip) && port == n2.port); } else { return false; } } public boolean equalsNonce(Object obj) { if (obj instanceof Peer) { Peer n2 = (Peer) obj; //return (ip.equals(n2.ip) && port == n2.port && nonce == n2.nonce); return nonce == n2.nonce; } else { return false; } } public long getLastAnswered() { return System.currentTimeMillis() - lastActionOnConnection; } // void writeTo(String out) { // if (connectionThread != null) { // connectionThread.writeString(out); //// if (Test.DEBUG) { //// System.out.println("outout: " + out); //// } // } // } public PeerSaveable toSaveable() { // ArrayList<Integer> loadedMsgsCloned = (ArrayList<Integer>) peerTrustData.loadedMsgs.clone(); // ArrayList<Integer> sendMessagesCloned = (ArrayList<Integer>) peerTrustData.sendMessages.clone(); // HashMap<Integer, RawMsg> pendingMessagesCloned = (HashMap<Integer, RawMsg>) peerTrustData.pendingMessages.clone(); // HashMap<Integer, RawMsg> pendingMessagesPublicCloned = (HashMap<Integer, RawMsg>) peerTrustData.pendingMessagesPublic.clone(); return new PeerSaveable(ip, port, lastAllMsgsQuerried, nonce, retries); } public boolean isConnected() { return connected; } public void setConnected(boolean connected) { this.connected = connected; } @Override public int compareTo(Peer o) { return o.getPriority() - getPriority(); // int ret = (int) (retries - o.retries); // // if (ret != 0) { // return ret; // } // // // int a = (int) (o.lastActionOnConnection - lastActionOnConnection); // // if (a != 0) { // return a; // } // // return (int) (o.lastAllMsgsQuerried - lastAllMsgsQuerried); } public int getPriority() { int a = 0; if (connected) { a += 2000; } if (nonce == 0) { a -= 1000; } if (ip.contains(":")) { a += 50; } if (peerTrustData != null) { if (peerTrustData.loadedMsgs != null) { a += peerTrustData.getMessageLoadedCount(); } a -= peerTrustData.badMessages * 100; } a += -retries * 200; return a; } public boolean iSameInstance(Peer p) { return super.equals(p); } public SocketChannel getSocketChannel() { return socketChannel; } public void setSocketChannel(SocketChannel socketChannel) { this.socketChannel = socketChannel; } // public void addWriteBuffer(ByteBuffer write) { // writeBuffers.add(write); // SelectionKey key = socketChannel.keyFor(ConnectionHandler.selector); // key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); // } // // public void addReadBuffer(ByteBuffer read) { // readBuffers.add(read); // } // // public ArrayList<ByteBuffer> getReadBuffers() { // return readBuffers; // } // // public ArrayList<ByteBuffer> getWriteBuffers() { // return writeBuffers; // } public void disconnect(String reason) { try { writeBufferLock.tryLock(2, TimeUnit.SECONDS); Log.put("DISCONNECT: " + reason, 30); setConnected(false); removeRequestedMsgs(); if (isConnecting && connectinThread != null) { connectinThread.interrupt(); } isConnecting = false; authed = false; if (selectionKey != null) { selectionKey.cancel(); } if (socketChannel != null) { // ByteBuffer a = ByteBuffer.allocate(1); // a.put((byte) 254); // a.flip(); // try { // int write = socketChannel.write(a); // //System.out.println("QUIT bytes: " + write); // } catch (IOException ex) { // } catch (NotYetConnectedException e) { // } if (socketChannel.isOpen()) { try { socketChannel.configureBlocking(false);//ToDo: hack socketChannel.close(); } catch (IOException ex) { } } } readBuffer = null; readBufferCrypted = null; writeBuffer = null; writeBufferCrypted = null; if (writeBufferLock.isHeldByCurrentThread()) { writeBufferLock.unlock(); } if (peerTrustData != null) { peerTrustData.pendingMessages = new HashMap<Integer, RawMsg>(); peerTrustData.pendingMessagesTimedOut = new HashMap<Integer, RawMsg>(); peerTrustData.pendingMessagesPublic = new HashMap<Integer, RawMsg>(); } } catch (InterruptedException ex) { Logger.getLogger(Peer.class.getName()).log(Level.SEVERE, null, ex); } Test.triggerOutboundthread(); } public void removeRequestedMsgs() { if (peerTrustData != null) { boolean tryLock = false; try { tryLock = MessageDownloader.requestedMsgsLock.tryLock(2, TimeUnit.SECONDS); if (!tryLock) { return; } for (MessageDownloader.RawMsgEntry msg : (ArrayList<MessageDownloader.RawMsgEntry>) MessageDownloader.requestedMsgs.clone()) { if (msg.requestedFromPeer == this) { MessageDownloader.requestedMsgs.remove(msg); System.out.print("R"); } } } catch (InterruptedException ex) { } finally { if (tryLock) { MessageDownloader.requestedMsgsLock.unlock(); } } } } public void ping() { if (getSelectionKey() == null || writeBuffer == null) { setConnected(false); return; } if (!getSelectionKey().isValid()) { System.out.println("selectionkey invalid11!"); //disconnect(); setConnected(false); return; } lastPinged = System.currentTimeMillis(); if (writeBufferLock.tryLock()) { if (writeBuffer.capacity() > 0) { writeBuffer.put((byte) 100); // System.out.println("pinged..."); } else { System.out.println("didnt ping, buffer has content..."); } writeBufferLock.unlock(); } else { System.out.println("Could not lock for ping!"); } setWriteBufferFilled(); } public SelectionKey getSelectionKey() { return selectionKey; } public void setSelectionKey(SelectionKey selectionKey) { this.selectionKey = selectionKey; } public boolean setWriteBufferFilled() { if (!isConnected()) { //System.out.println("::::"); //throw new RuntimeException("dafuq !!!!!!!!!"); return false; } //System.out.println("Bytes: " + writeBuffer.position()); boolean remainingBytes; if (writeBuffer == null) { return false; } //// ByteBuffer localWriteBuffer = writeBuffer; //// //// writeBufferLock.lock(); //// //// int writtenBytes = 0; //// localWriteBuffer.flip(); //switch buffer for reading //// try { //// writtenBytes = writeBytesToPeer(localWriteBuffer); //// } catch (IOException ex) { //// ex.printStackTrace(); //// //// setConnected(false); //// System.out.println("error writing bytes to peer."); //// try { //// socketChannel.close(); //// } catch (IOException ex1) { //// } //// //// } //// Test.outBytes += writtenBytes; //// //// if (writeBufferCrypted == null) { //// remainingBytes = localWriteBuffer.hasRemaining(); //// } else { //// writeBufferCrypted.flip(); //// remainingBytes = writeBufferCrypted.hasRemaining(); //// writeBufferCrypted.compact(); //// } //// //// localWriteBuffer.compact(); //// //// writeBufferLock.unlock(); //// //// if (!remainingBytes) { //// return true; //// } // if (writeBuffer.remaining() < 1024 * 1024) { // ByteBuffer allocate = ByteBuffer.allocate(writeBuffer.capacity() * 2); // allocate.put(writeBuffer.array()); // allocate.position(writeBuffer.position()); // writeBuffer = allocate; //// System.out.println("writeBuffer voll, wurde verdoppelt..."); // } // System.out.println("Writing stucked..."); if (getSelectionKey().isValid()) { try { getSelectionKey().selector().wakeup(); getSelectionKey().interestOps(getSelectionKey().interestOps() | SelectionKey.OP_WRITE); getSelectionKey().selector().wakeup(); //System.out.println("added op_write..."); } catch (CancelledKeyException e) { //disconnect(); System.out.println("cancelled key exception"); } } else { System.out.println("key is not valid"); disconnect("key is not valid"); } return false; } int writeBytesToPeer(ByteBuffer writeBuffer) throws IOException { int writtenBytes; if (writeBufferCrypted == null) { writtenBytes = getSocketChannel().write(writeBuffer); } else { //TODO groesse anpassen vom crypted buffer byte[] buffer = new byte[writeBuffer.remaining()]; writeBuffer.get(buffer); byte[] encryptedBytes = writeKey.encrypt(buffer); if (writeBufferCrypted.remaining() < encryptedBytes.length) { //buffer zu klein :( ByteBuffer newBuffer = ByteBuffer.allocate(writeBufferCrypted.capacity() + encryptedBytes.length); newBuffer.put(writeBufferCrypted); writeBufferCrypted = newBuffer; } writeBufferCrypted.put(encryptedBytes); writeBufferCrypted.flip(); writtenBytes = getSocketChannel().write(writeBufferCrypted); writeBufferCrypted.compact(); // System.out.println("written bytes to node: " + writtenBytes); //System.out.println("crypted bytes: " + Utils.bytesToHexString(buffer) + " to " + Utils.bytesToHexString(encryptedBytes)); } return writtenBytes; } /** * NOTICE: does not flush the writeStream introduces message to node, * includes channel if not already sent. * * @param m - message to introduce */ public synchronized void writeMessage(RawMsg m) { try { //may be setted to null during work... ByteBuffer localWriteBuffer = writeBuffer; //Log.put("try to introduce msg to node " + nonce, 200); if (localWriteBuffer == null || readBuffer == null) { System.out.println("couldnt send msg, no buffers..."); return; } if (m.database_Id == -1 || m.key.database_id == -1) { //Main.sendBroadCastMsg("HOLY SHIT - nudm3284mz28423n4znc75z34c578n3485zc3857zc8345"); try { throw new RuntimeException("HOLY SHIT - nudm3284mz28423n4znc75z34c578n3485zc3857zc8345 " + m.database_Id + " " + m.key.database_id); } catch (RuntimeException e) { e.printStackTrace(); } return; } // if (peerTrustData.sendMessages.contains(m.database_Id)) { // return; // } // // if (peerTrustData.isFilteringAddresses() && !peerTrustData.isPermittedAddress(m.key.database_id)) { // //System.out.println("peer doesnt want messages for this channel: " + m.key.getPubKey()); // return; // } //peerTrustData.sendMessages.add(m.database_Id); //Test.messageStore.addMsgIntroducedToHim(peerTrustData.internalId, m.database_Id); //System.out.println("added to db: " + peerTrustData.internalId + " - " + m.database_Id); ECKey k = m.key; if (!peerTrustData.keyToIdMine.contains(k.database_id)) { // if (k.getPubKey().length != 33) { // System.out.println("Dbdzudgn268rtgx6345g345m: " + " len: " + k.getPubKey().length); // byte[] b = new byte[33]; // int i = 0; // for (byte bb : k.getPubKey()) { // b[i] = bb; // i++; // } // // k = new ECKey(null, b); // // System.out.println("Dbdzudgn268rtgx6345g345m: " + " len: " + k.getPubKey().length); // } writeBufferLock.lock(); if (writeBuffer == null) { writeBufferLock.unlock(); return; } peerTrustData.keyToIdMine.add(k.database_id); //int indexOf = keyToIdMine.indexOf(k); int indexOf = m.key.database_id; localWriteBuffer.put((byte) 4); localWriteBuffer.put(k.getPubKey()); localWriteBuffer.putInt(indexOf); //System.out.println("Msg index: " + indexOf); writeBufferLock.unlock(); } if (m.public_type == -1) { throw new RuntimeException("omg!"); } //Log.put("try to get lock for writebuffer for node " + nonce, 200); writeBufferLock.lock(); //Log.put("got lock: " + nonce, 200); if (writeBuffer == null) { //Log.put("writebuffer null: " + nonce, 200); writeBufferLock.unlock(); return; } //int indexOfKey = keyToIdMine.indexOf(k); int indexOfKey = k.database_id; //Log.put("asdf " + nonce, 200); if (writeBuffer.remaining() < 1 + 4 + 1 + 8 + 4 + 4) { ByteBuffer oldbuffer = writeBuffer; writeBuffer = ByteBuffer.allocate(writeBuffer.capacity() + 50); writeBuffer.put(oldbuffer.array()); writeBuffer.position(oldbuffer.position()); System.out.println("writebuffer was raised..."); } //Log.put("gd2eqe2: " + nonce, 200); writeBuffer.put((byte) 5); writeBuffer.putInt(indexOfKey); writeBuffer.put(m.public_type); writeBuffer.putLong(m.timestamp); writeBuffer.putInt(m.nonce); writeBuffer.putInt(m.database_Id);//TODO long zu int machen mit offset falls db zu gross!! //Log.put("try to unlock: " + nonce + " isLockedByMe: " + writeBufferLock.isHeldByCurrentThread(), 200); writeBufferLock.unlock(); Log.put("Introduced message to node: " + m.database_Id + " " + nonce, 40); //should be run later manually... //// boolean sureWrittenToPeer = setWriteBufferFilled(); //// //// //System.out.println("wrote msg to peer: " + ip + " " + m.database_Id); //// if (!sureWrittenToPeer) { //// //TODO //// } } catch (Throwable e) { e.printStackTrace(); } } public void sendChannelToFilter(ECKey k) { int pubkeyId = Test.messageStore.getPubkeyId(k); k.database_id = pubkeyId; if (writeBuffer == null || readBuffer == null) { System.out.println("couldnt send msg, no buffers..."); return; } if (k.database_id == -1) { //Main.sendBroadCastMsg("HOLY SHIT - nudm3284mz28423n4znc75z34c578n3485zc3857zc8345"); try { throw new RuntimeException("HOLY SHIT - xXnudm3284mz28423n4znc75z34c578n3485zc3857zc8345 " + k.database_id); } catch (RuntimeException e) { e.printStackTrace(); } return; } if (!peerTrustData.keyToIdMine.contains(k.database_id)) { // if (k.getPubKey().length != 33) { // System.out.println("Dbdzudgn268rtgx6345g345m: " + " len: " + k.getPubKey().length); // byte[] b = new byte[33]; // int i = 0; // for (byte bb : k.getPubKey()) { // b[i] = bb; // i++; // } // // k = new ECKey(null, b); // // System.out.println("Dbdzudgn268rtgx6345g345m: " + " len: " + k.getPubKey().length); // } writeBufferLock.lock(); peerTrustData.keyToIdMine.add(k.database_id); //int indexOf = keyToIdMine.indexOf(k); int indexOf = k.database_id; writeBuffer.put((byte) 4); writeBuffer.put(k.getPubKey()); writeBuffer.putInt(indexOf); //System.out.println("Msg index: " + indexOf); writeBufferLock.unlock(); } writeBufferLock.lock(); int indexOf = k.database_id; writeBuffer.put((byte) 60); writeBuffer.putInt(indexOf); writeBufferLock.unlock(); } public void migratePeer(Peer otherPeer) { // peerTrustData.loadedMsgs = peerTrustData.loadedMsgs; requestedMsgs = otherPeer.requestedMsgs; // peerTrustData.sendMessages = peerTrustData.sendMessages; // peerTrustData.pendingMessages = peerTrustData.pendingMessages; //keyToIdHis = otherPeer.keyToIdHis; //keyToIdMine = otherPeer.keyToIdMine; // peerTrustData.synchronizedMessages = peerTrustData.synchronizedMessages; // peerTrustData.lastSuccessfulySendMessageHeader = peerTrustData.lastSuccessfulySendMessageHeader; } public boolean peerIsHigher() { return Test.NONCE > nonce; } public boolean isFullConnected() { //System.out.println("hmm : " + (writeBufferCrypted != null)); return (writeBufferCrypted != null && readBufferCrypted != null); //return (writeBufferCrypted != null); } public String getIp() { return ip; } public int getPort() { return port; } public boolean isAuthed() { return authed; } public boolean isCryptedConnection() { return readBufferCrypted != null; } public PeerTrustData getPeerTrustData() { return peerTrustData; } public HashMap<Integer, ECKey> getKeyToIdHis() { return getPeerTrustData().keyToIdHis; } public ArrayList<Integer> getKeyToIdMine() { return getPeerTrustData().keyToIdMine; } public ECKey getId2KeyHis(int cnt) { return getPeerTrustData().id2KeyHis(cnt); } void addPendingMessage(int messageId, RawMsg rawMsg) { getPeerTrustData().addPendingMessage(messageId, rawMsg); } public HashMap<Integer, RawMsg> getPendingMessages() { return getPeerTrustData().getPendingMessages(); } public HashMap<Integer, RawMsg> getPendingMessagesTimedOut() { return getPeerTrustData().getPendingMessagesTimedOut(); } public HashMap<Integer, RawMsg> getPendingMessagesPublic() { return getPeerTrustData().getPendingMessagesPublic(); } /** * peer trust data have to be set, otherwise NULLPOINTER! * * @return */ public ArrayList<Integer> getLoadedMsgs() { return getPeerTrustData().loadedMsgs; } synchronized void addLoadedMsg(int database_Id) { ArrayList<Integer> temp = getLoadedMsgs(); temp.add(database_Id); ArrayList<Integer> loadedMsgs = (ArrayList<Integer>) temp.clone(); if (loadedMsgs.size() > 500) { ArrayList<Integer> loadedMsgsNew = new ArrayList<Integer>(200); //copy last 200 from old to new. for (int i = loadedMsgs.size() - 200; i < loadedMsgs.size(); i++) { loadedMsgsNew.add(loadedMsgs.get(i)); } getPeerTrustData().loadedMsgs = loadedMsgsNew; getPeerTrustData().loadedMsgsCount += loadedMsgs.size() - 200; Log.put("shrinked loadedmsgs: " + nonce, 3); } } /** * Returns -5000 if no trustdata is set! * * @return */ public int getMessageLoadedCount() { if (peerTrustData == null) { return -5000; } else { return peerTrustData.getMessageLoadedCount(); } } }