/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.redPandaLib.services; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import static java.lang.Thread.sleep; import java.nio.ByteBuffer; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLIntegrityConstraintViolationException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; import org.redPandaLib.Main; import org.redPandaLib.NewMessageListener; import org.redPandaLib.SpecialChannels; import org.redPandaLib.core.*; import org.redPandaLib.core.ImageInfos.Infos; import static org.redPandaLib.core.Test.NAT_OPEN; import static org.redPandaLib.core.Test.inBytes; import static org.redPandaLib.core.Test.messageStore; import static org.redPandaLib.core.Test.outBytes; import static org.redPandaLib.core.Test.peerList; import org.redPandaLib.core.messages.BlockMsg; import org.redPandaLib.core.messages.DeliveredMsg; import org.redPandaLib.core.messages.ImageMsg; import org.redPandaLib.core.messages.InfoMsg; import org.redPandaLib.core.messages.RawMsg; import org.redPandaLib.core.messages.TextMessageContent; import org.redPandaLib.core.messages.TextMsg; import org.redPandaLib.crypt.ECKey; import org.redPandaLib.crypt.Sha256Hash; import org.redPandaLib.crypt.Utils; import org.redPandaLib.database.DirectMessageStore; import org.redPandaLib.database.HsqlConnection; /** * MAX_PERMITS * * @author robin */ public class MessageVerifierHsqlDb { private static final int loadMsgsPerQuery = 200; public static final MyThread myThread = new MyThread(); static ExecutorService threadPool = Executors.newFixedThreadPool(4); private static int runningThreads = 0; public static boolean PAUSE = false; public static ArrayList<ImageMsg> imageMsgs = new ArrayList<ImageMsg>(); private static long lastRemovedOldMessages = 0; private static ExecutorService sendDeliveredMsgsThreads = Executors.newFixedThreadPool(2); private static long lastDbReconnected = 0; public static int MAX_PERMITS = 10; public static Semaphore sem = new Semaphore(MAX_PERMITS); public static boolean USES_UNREAD_STATUS = false; public static long lastRun = 0; public static long LAST_AUTO_GENERATED_BLOCK = 0; public static boolean notsendremoveadownloadedmsg = true; private static Thread lastThread = null; public static final ReentrantLock filesSystemLockForImages = new ReentrantLock(); //Need this lock because if check for all blocks then one might not be finished. public static void start() { myThread.setPriority(Thread.MIN_PRIORITY); myThread.start(); // new Thread() { // // @Override // public void run() { // while (!Main.shutdown) { // // try { // System.out.println("Database check alive: " + Test.messageStore.getConnection().isValid(2)); // if (!Test.messageStore.getConnection().isValid(2)) { // // if (System.currentTimeMillis() - lastDbReconnected > 1000 * 15) { // Test.hsqlConnection.reconnect(); // lastDbReconnected = System.currentTimeMillis(); // } // } // } catch (SQLException ex) { // Logger.getLogger(MessageVerifierHsqlDb.class.getName()).log(Level.SEVERE, null, ex); // } // try { // sleep(60 * 1000); // } catch (InterruptedException ex) { // Logger.getLogger(MessageVerifierHsqlDb.class.getName()).log(Level.SEVERE, null, ex); // } // } // } // }.start(); } public static void trigger() { myThread.interrupt(); } static class MyThread extends Thread { @Override public void run() { // threadPool = Executors.newFixedThreadPool(4); final String orgName = Thread.currentThread().getName(); Thread.currentThread().setName(orgName + " - MessageVerifier"); try { sleep(2000); } catch (InterruptedException ex) { } while (!Main.shutdown) { lastRun = System.currentTimeMillis(); if ((System.currentTimeMillis() - lastRemovedOldMessages) > 1000 * 60 * 60) { lastRemovedOldMessages = System.currentTimeMillis(); if (Settings.REMOVE_OLD_MESSAGES) { Test.messageStore.removeOldMessages(System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 7); } //currently buggy moves to many messages ?!? //Test.messageStore.moveChannelMessagesToHistory(System.currentTimeMillis() - 1000L * 60L * 60L * 24L * 30L * 2L); if (Test.messageStore.getConnection() instanceof HsqlConnection) { Test.messageStore.checkpoint(); System.out.println("checkpointed!!!!!"); } } try { boolean breaked = false; if (PAUSE) { try { sleep(1000); } catch (InterruptedException ex) { } continue; } final Connection connection = Test.messageStore.getConnection(); Log.put("prepare select... " + connection.isValid(2), 70); // if (!connection.isValid(2)) { // // // if (System.currentTimeMillis() - lastDbReconnected > 1000 * 60 * 5) { // Test.hsqlConnection.reconnect(); // lastDbReconnected = System.currentTimeMillis(); // } // sleep(500); // continue; // } //get Key Id String query = "SELECT message_id, pubkey.pubkey_id, pubkey, public_type, timestamp, nonce, signature, content from message left join pubkey on (pubkey.pubkey_id = message.pubkey_id) WHERE verified = 0 order by timestamp LIMIT " + loadMsgsPerQuery; PreparedStatement pstmt = connection.prepareStatement(query); pstmt.setQueryTimeout(2); Log.put("selecting", 70); ResultSet executeQuery = pstmt.executeQuery(); Log.put("finish!", 70); int cnt = 0; while (executeQuery.next()) { Log.put("new msg to verify... ", 70); cnt++; final int message_id = executeQuery.getInt("message_id"); final int pubkey_id = executeQuery.getInt("pubkey.pubkey_id"); final byte[] pubkey = executeQuery.getBytes("pubkey"); ECKey ecKey = new ECKey(null, pubkey); ecKey.database_id = pubkey_id; byte public_type = executeQuery.getByte("public_type"); final long timestamp = executeQuery.getLong("timestamp"); int nonce = executeQuery.getInt("nonce"); byte[] signature = executeQuery.getBytes("signature"); byte[] content = executeQuery.getBytes("content"); MessageDownloader.publicMsgsLoadedLock.lock(); MessageDownloader.publicMsgsLoaded--; // if (MessageDownloader.publicMsgsLoaded < 0) { // MessageDownloader.publicMsgsLoaded = 0; // } Log.put("msgs to verify: " + MessageDownloader.publicMsgsLoaded, 100); MessageDownloader.publicMsgsLoadedLock.unlock(); //Stick if (signature == null) { System.out.println("is this a stick?"); continue; } RawMsg tempRawMsg = new RawMsg(timestamp, nonce, signature, content, false); tempRawMsg.database_Id = message_id; tempRawMsg.key = ecKey; tempRawMsg.public_type = public_type; final RawMsg rawMsg = tempRawMsg; Runnable runnable; runnable = new Runnable() { @Override public void run() { try { setPriority(Thread.MIN_PRIORITY); final String orgName = Thread.currentThread().getName(); if (orgName.length() < 20) { Thread.currentThread().setName(orgName + " - verify and broadcast thread"); } boolean verify = false; try { verify = rawMsg.verify(); } catch (NullPointerException ex) { Test.sendStacktrace(ex); } if (Main.shutdown) { return; } try { if (verify) { final RawMsg message = rawMsg.toSpecificMsgType(); //nur damit es auch wirklich da ist... bugsuche... message.database_Id = message_id; message.key.database_id = pubkey_id; // synchronized (MessageHolder.msgs) { // int index = MessageHolder.msgs.indexOf(m); // MessageHolder.msgs.set(index, message); // } //currentl disabled!! //if (message.public_type == 20 && MessageDownloader.getLatestBlockTime(pubkey_id) > message.timestamp) { if (false) { //this message was not requestet and is old, delete it! PreparedStatement stmt2 = connection.prepareStatement("delete FROM message WHERE message_id = ?"); stmt2.setInt(1, message_id); stmt2.executeUpdate(); stmt2.close(); Test.messageStore.resetMessageCounter(); if (notsendremoveadownloadedmsg) { Main.sendBroadCastMsg("removed a downloaded message because it is already in a block"); notsendremoveadownloadedmsg = false; } System.out.println("removed a downloaded message because it is already in a block"); } else { boolean succesfullCommited = false; while (!succesfullCommited) { PreparedStatement stmt = null; try { //System.out.println("signature richtig..."); stmt = connection.prepareStatement("update message SET verified = true WHERE message_id = ?"); stmt.setInt(1, message_id); stmt.executeUpdate(); stmt.close(); succesfullCommited = true; } catch (SQLIntegrityConstraintViolationException e) { Log.put("Could not update verified status of message, have to try again....", 150); stmt.close(); sleep(100); } } if (message.public_type == BlockMsg.PUBLIC_TYPE) { System.out.println("i found a block!!!"); //double lock, but is ok since we have a reentrance lock MessageDownloader.channelIdToLatestBlockTimeLock.lock(); Long get = MessageDownloader.getLatestBlockTime(pubkey_id); if (get < message.timestamp) { MessageDownloader.channelIdToLatestBlockTime.put(pubkey_id, message.timestamp); } MessageDownloader.channelIdToLatestBlockTimeLock.unlock(); if (message.readable) { // System.out.println("hex: " + Utils.bytesToHexString(message.decryptedContent)); BlockMsg blockMsg = (BlockMsg) message; String text = "Block: " + blockMsg.getMessageCount() + " msgs (" + blockMsg.content.length / 1024. + " kb)."; boolean fromMe = (blockMsg.getIdentity() == Test.localSettings.identity); Test.messageStore.addDecryptedContent(blockMsg.getKey().database_id, (int) blockMsg.database_Id, BlockMsg.BYTE, blockMsg.timestamp, text.getBytes(), ((BlockMsg) blockMsg).getIdentity(), fromMe, blockMsg.nonce, blockMsg.public_type); // TextMessageContent textMessageContent = new TextMessageContent(blockMsg.database_Id, blockMsg.key.database_id, blockMsg.public_type, TextMsg.BYTE, blockMsg.timestamp, blockMsg.decryptedContent, blockMsg.channel, blockMsg.getIdentity(), text, true); // textMessageContent.read = true; // for (NewMessageListener listener : Main.listeners) { // listener.newMessage(textMessageContent); // } //generate Count and Hash! try { HashAndCount generateMyHashAndMsgCount = generateMyHashAndMsgCount(blockMsg); if (generateMyHashAndMsgCount == null) { return; } int msgcount = generateMyHashAndMsgCount.cnt; int hash = generateMyHashAndMsgCount.hash; System.out.println("MyCnt: " + msgcount); System.out.println("BlockCnt: " + blockMsg.getMessageCount()); System.out.println("Hashes: " + hash + " - " + blockMsg.getContentHash()); //compare cnt and hash: if (blockMsg.getMessageCount() != msgcount || blockMsg.getContentHash() != hash) { System.out.println("Count or hash not equal, syncing block with my database!"); ByteBuffer wrap = ByteBuffer.wrap(blockMsg.decryptedContent); //read block! //skip header wrap.get(); //BlockMsg.BYTE); //cmd for block wrap.getLong();//indenity who generated the block wrap.getInt();//msgcount wrap.getInt();//hash int cnt = 0; while (wrap.remaining() >= 8 + 4 + 4 + 8 + 4) { cnt++; //System.out.println("cnt: " + cnt); long timestamp = wrap.getLong(); int nonce = wrap.getInt(); int message_type = wrap.getInt(); long identity = wrap.getLong(); int contentLenght = wrap.getInt(); //System.out.println("contentlen: " + contentLenght); if (contentLenght > 1024 * 200) { System.out.println("Message content too big..."); continue; } byte[] content = null; if (contentLenght > 0) { content = new byte[contentLenght]; try { wrap.get(content); } catch (Throwable e) { System.out.println("Wrong length!!1 - invalid block"); break; } } fromMe = (identity == Test.localSettings.identity); boolean added = Test.messageStore.addDecryptedContent(pubkey_id, TextMsg.BYTE, timestamp, content, identity, fromMe, nonce, (byte) 20); if (added) { String string = ""; if (contentLenght > 0) { string = new String(content, "UTF-8"); } TextMessageContent textmsgcontent = new TextMessageContent(-1, pubkey_id, (byte) 20, message_type, timestamp, content, blockMsg.channel, identity, string, fromMe); for (NewMessageListener listener : Main.listeners) { listener.newMessage(textmsgcontent); } if (USES_UNREAD_STATUS && !fromMe) { Test.messageStore.addUnreadMessage(message_id); } } } System.out.println("rdy!!! #################"); //we have to look if the block and my msgs are now the same: generateMyHashAndMsgCount = generateMyHashAndMsgCount(blockMsg); if (generateMyHashAndMsgCount == null) { return; } msgcount = generateMyHashAndMsgCount.cnt; hash = generateMyHashAndMsgCount.hash; if (message.channel.isWriteable()) { if (blockMsg.getMessageCount() != msgcount || blockMsg.getContentHash() != hash) { System.out.println("i have to generate a new block"); if (System.currentTimeMillis() - LAST_AUTO_GENERATED_BLOCK > 1000 * 60 * 60 * 4 && System.currentTimeMillis() - blockMsg.timestamp < 1000 * 60 * 10) { Blocks.generate(blockMsg.channel); LAST_AUTO_GENERATED_BLOCK = System.currentTimeMillis(); } } else { System.out.println("all fine"); } } } else { System.out.println("block and my database are the same!!! yeah!"); } } catch (SQLException ex) { Logger.getLogger(DirectMessageStore.class.getName()).log(Level.SEVERE, null, ex); } catch (UnsupportedEncodingException ex) { Logger.getLogger(MessageVerifierHsqlDb.class.getName()).log(Level.SEVERE, null, ex); } } else { System.out.println("block not for me..."); } System.out.println("New block saved and send, doing cleanup..."); //remove old block: int removeMessagesFromChannel = Test.messageStore.removeMessagesFromChannel(pubkey_id, BlockMsg.PUBLIC_TYPE, message.timestamp); System.out.println("removed old blocks: " + removeMessagesFromChannel); //remove old messages which are encrypted and now saved in the new block (only necessary data)... removeMessagesFromChannel = Test.messageStore.removeMessagesFromChannel(pubkey_id, (byte) 20, message.timestamp); System.out.println("removed old encrypted messages: " + removeMessagesFromChannel); } else // check for other msgs types with first byte of decrypted content { if (message instanceof TextMsg) { TextMsg textMsg = (TextMsg) message; long identity = textMsg.getIdentity(); boolean fromMe = (identity == Test.localSettings.identity); Test.messageStore.addDecryptedContent(pubkey_id, message_id, TextMsg.BYTE, textMsg.timestamp, textMsg.getText(), textMsg.getIdentity(), fromMe, textMsg.nonce, textMsg.public_type); TextMessageContent fromTextMsg = TextMessageContent.fromTextMsg(textMsg, fromMe); for (NewMessageListener listener : Main.listeners) { listener.newMessage(fromTextMsg); } if (USES_UNREAD_STATUS && !fromMe) { Test.messageStore.addUnreadMessage(message_id); } //send delivered msg if (Settings.SEND_DELIVERED_MSG && SpecialChannels.isSpecial(pubkey) == null) { sendDeliveredMessage(message); } //TODO: REMOVE WHEN NOT NEEDED ANYMORE, generating stats for debugging and send to MainChannel. if (SpecialChannels.isSpecial(pubkey) != null) { //System.out.println("Special channel text: " + fromTextMsg.text); if (fromTextMsg.text.equals("status")) { System.out.println("sending status"); String out = "Messages in db: "; out += Test.messageStore.getMessageCount() + " - to verify: " + Test.messageStore.getMessageCountToVerify(); out += "\n\n"; int actCons = 0; ArrayList<Peer> list = Test.getClonedPeerList(); Collections.sort(list); for (Peer peer : list) { if (peer.isConnected()) { actCons++; } } out += "\nConnected to " + actCons + "/" + list.size() + " peers. (NAT type: " + (NAT_OPEN ? "open" : "closed") + ")"; out += "\nTraffic: " + inBytes / 1024. + " kb / " + outBytes / 1024. + " kb."; Main.sendBroadCastMsg(out); } else if (fromTextMsg.text.equals("knownTrigger")) { System.out.println("trigger knwon channels by main channel..."); new Thread() { @Override public void run() { KnownChannels.updateMyChannels(); KnownChannels.sendAllKnownChannels(); } }.start(); } } } else if (message instanceof DeliveredMsg) { DeliveredMsg deliveredMsg = (DeliveredMsg) message; //System.out.println(deliveredMsg.getNick() + " in " + deliveredMsg.getChannel().name + " hat die Nachrich bekommen: " + deliveredMsg.timestamp + " " + deliveredMsg.nonce); //TextMsg build = TextMsg.build(deliveredMsg.getChannel(), deliveredMsg.getIdentity() + " in " + deliveredMsg.getChannel().getName() + " hat die Nachrich bekommen: " + formatTime(new Date(deliveredMsg.timestamp)) + " " + deliveredMsg.nonce); Test.messageStore.addDecryptedContent(pubkey_id, message_id, DeliveredMsg.BYTE, deliveredMsg.timestamp, deliveredMsg.decryptedContent, deliveredMsg.getIdentity(), false, deliveredMsg.nonce, deliveredMsg.public_type); TextMessageContent fromTextMsg = TextMessageContent.fromDeliveredMsg(deliveredMsg, false); for (NewMessageListener listener : Main.listeners) { listener.newMessage(fromTextMsg); } } else if (message instanceof ImageMsg) { System.out.println("Found a IMAGE!"); ImageMsg imageMsg = (ImageMsg) message; int partsForImage = imageMsg.getParts(); int partNumber = imageMsg.getPartCount(); filesSystemLockForImages.lock(); try { String partFileName = "imgpart-" + imageMsg.getTimestamp() + "-" + imageMsg.getIdentity() + "-" + partNumber + "-" + partsForImage + ".part"; writeBytesToFile(imageMsg.getImageBytes(), Test.imageStoreFolder + partFileName); System.out.println("wrote bytes into part file"); System.out.println("check for all exiting parts..."); boolean missing = false; for (int i = 0; i < partsForImage; i++) { File file = new File(Test.imageStoreFolder + "imgpart-" + imageMsg.getTimestamp() + "-" + imageMsg.getIdentity() + "-" + i + "-" + partsForImage + ".part"); if (!file.exists()) { missing = true; break; } } System.out.println("part missing: " + missing); if (!missing) { String pathToFile = Test.imageStoreFolder + "img-" + imageMsg.getChannel().getName() + "-" + imageMsg.getTimestamp() + ".jpg"; File outFile = new File(pathToFile); try { FileOutputStream fileOutputStream = new FileOutputStream(outFile); try { for (int i = 0; i < partsForImage; i++) { File readFile = new File(Test.imageStoreFolder + "imgpart-" + imageMsg.getTimestamp() + "-" + imageMsg.getIdentity() + "-" + i + "-" + partsForImage + ".part"); byte[] buffer = new byte[1024 * 50]; InputStream ios = null; int readBytes = 0; try { ios = new FileInputStream(readFile); //ToDoE: file not found exception ?!?, THREADED!!! need to sync that all are finished while ((readBytes = ios.read(buffer)) != -1) { fileOutputStream.write(buffer, 0, readBytes); } } finally { try { if (ios != null) { ios.close(); } } catch (IOException e) { } } readFile.delete(); } Infos infos = Test.imageInfos.getInfos(pathToFile); if (infos == null) { Log.put("image is no image?", 0); } else { String imageInfos = pathToFile + "\n" + infos.width + "\n" + infos.heigth; long identity = imageMsg.getIdentity(); boolean fromMe = (identity == Test.localSettings.identity); Test.messageStore.addDecryptedContent(pubkey_id, message_id, ImageMsg.BYTE, imageMsg.getTimestamp(), imageInfos.getBytes(), imageMsg.getIdentity(), fromMe, imageMsg.nonce, imageMsg.public_type); TextMessageContent fromTextMsg = TextMessageContent.fromImageMsg(imageMsg, fromMe, imageInfos); for (NewMessageListener listener : Main.listeners) { listener.newMessage(fromTextMsg); } if (USES_UNREAD_STATUS && !fromMe) { Test.messageStore.addUnreadMessage(message_id); } //send delivered msg if (Settings.SEND_DELIVERED_MSG && SpecialChannels.isSpecial(pubkey) == null) { sendDeliveredMessage(message); } } } catch (IOException ex) { Logger.getLogger(ImageSaver.class.getName()).log(Level.SEVERE, null, ex); } finally { try { fileOutputStream.close(); } catch (IOException ex) { Logger.getLogger(MessageVerifierHsqlDb.class.getName()).log(Level.SEVERE, null, ex); } } } catch (FileNotFoundException ex) { Logger.getLogger(ImageSaver.class.getName()).log(Level.SEVERE, null, ex); } } } catch (Throwable e) { Test.sendStacktrace(e); } finally { filesSystemLockForImages.unlock(); } // imageMsgs.add((ImageMsg) message); // // System.out.println("in ram: " + imageMsgs.size()); // // ArrayList<ImageMsg> clonedList = (ArrayList<ImageMsg>) imageMsgs.clone(); // // //search for complete ImageSet // // HashMap<String, ArrayList<ImageMsg>> map = new HashMap<String, ArrayList<ImageMsg>>(); // // // for (ImageMsg msg : clonedList) { // String imgKey = "" + msg.getTimestamp() + msg.getIdentity(); // // if (!map.containsKey(imgKey)) { // map.put(imgKey, new ArrayList<ImageMsg>()); // } // ArrayList<ImageMsg> get = map.get(imgKey); // get.add(msg); // // System.out.println("PARTS: " + get.size()); // // if (msg.getParts() == get.size()) { // // // // System.out.println("Alle Parts geladen für img: " + imgKey); // // Collections.sort(get, new Comparator<ImageMsg>() { // @Override // public int compare(ImageMsg o1, ImageMsg o2) { // return o1.getPartCount() - o2.getPartCount(); // } // }); // // // System.out.println("sorted..."); // // for (ImageMsg asdf : get) { // System.out.println("BLOCK: " + asdf.getPartCount()); // } // // // // ByteBuffer imageBytesBuffer = ByteBuffer.allocate(get.get(0).getParts() * get.get(0).getImageBytes().length); // // int bytesUsed = 0; // // for (ImageMsg asdf : get) { // System.out.println("BLOCK: " + asdf.getPartCount()); // byte[] localBytes = asdf.getImageBytes(); // // imageBytesBuffer.put(localBytes); // bytesUsed += localBytes.length; // // imageMsgs.remove(asdf); // // } // // imageBytesBuffer.flip(); // // byte[] wdwdw = new byte[bytesUsed]; // imageBytesBuffer.get(wdwdw); // // new ImageSaver(Test.imageStoreFolder).saveImage(wdwdw, "img-" + get.get(0).getTimestamp() + ".jpg"); // // String fileName = Test.imageStoreFolder + "img-" + get.get(0).getTimestamp() + ".jpg"; // ByteArrayInputStream byteInputStream = new ByteArrayInputStream(wdwdw); // BufferedImage read = ImageIO.read(byteInputStream); // // String imageInfos = fileName + "\n" + read.getWidth() + "\n" + read.getHeight(); // // ImageMsg firstMsg = get.get(0); // // long identity = firstMsg.getIdentity(); // boolean fromMe = (identity == Test.localSettings.identity); // // Test.messageStore.addDecryptedContent(pubkey_id, message_id, ImageMsg.BYTE, imageInfos.getBytes(), firstMsg.getIdentity(), fromMe); // TextMessageContent fromTextMsg = TextMessageContent.fromImageMsg(firstMsg, fromMe, imageInfos); // // for (NewMessageListener listener : Main.listeners) { // listener.newMessage(fromTextMsg); // } // // //send delivered msg // if (Settings.SEND_DELIVERED_MSG && SpecialChannels.isSpecial(pubkey) == null) { // DeliveredMsg build = DeliveredMsg.build(message.getChannel(), message.public_type, message.timestamp, message.nonce); // RawMsg addMessage = MessageHolder.addMessage(build); // Test.broadcastMsg(addMessage); // } // } // } //new ImageSaver("").saveImage("", "loaded.jpg"); } else if (message instanceof InfoMsg) { try { InfoMsg infoMsg = (InfoMsg) message; long identity = infoMsg.getIdentity(); HashMap<ECKey, Integer> levels = infoMsg.getLevels(); int pubKeyIdFrom = Test.messageStore.getPubkeyId(infoMsg.getKey()); for (ECKey channel : levels.keySet()) { int pubKeyIdfor = Test.messageStore.getPubkeyId(channel); int level = levels.get(channel) + 1; Test.messageStore.addKnownChannel(pubKeyIdfor, identity, pubKeyIdFrom, level); Log.put("add from other node channelLevels: " + Utils.bytesToHexString(channel.getPubKey()) + " lvel: " + level + " from: " + pubKeyIdFrom, 0); } } catch (Throwable e) { e.printStackTrace(); } } else { //System.out.println("No textmsg?"); } } if (Settings.BROADCAST_MSGS_AFTER_VERIFICATION) { if (timestamp > System.currentTimeMillis() - 1000L * 60L * 60L * 24L * 7L) { Runnable sendRunnable = new Runnable() { @Override public void run() { final String orgName = Thread.currentThread().getName(); if (orgName.length() < 20) { Thread.currentThread().setName(orgName + " - broadCastMsg"); } Test.broadcastMsg(message); } }; sendDeliveredMsgsThreads.submit(sendRunnable); } } } } else { try { System.out.println("wrong signature..."); System.out.println("pubkey bytes : " + Channel.byte2String(rawMsg.key.getPubKey())); System.out.println("signature bytes : " + Utils.bytesToHexString(rawMsg.signature)); System.out.println("len : " + rawMsg.signature.length); Peer loadedFrom = null; for (Peer peer : Test.getClonedPeerList()) { if (peer.getPeerTrustData() == null || peer.getLoadedMsgs() == null) { continue; } ArrayList<Integer> loadedMsgs = (ArrayList<Integer>) peer.getLoadedMsgs().clone(); for (int i : loadedMsgs) { if (i == message_id) { loadedFrom = peer; System.out.println("loaded from peer: " + peer.getIp() + ":" + peer.getPort()); peer.getPeerTrustData().badMessages++; peer.disconnect("bad signature!!!"); System.out.println("disconnect..."); //Test.peerTrusts.remove(peer.peerTrustData); //System.out.println("REMOVED PEER TRUST!"); } } } if (loadedFrom != null && loadedFrom.getPeerTrustData() != null) { for (Entry<Integer, ECKey> a : loadedFrom.getKeyToIdHis().entrySet()) { System.out.println("keyToId - id: " + a.getKey() + " key: " + Channel.byte2String(a.getValue().getPubKey())); } } } catch (Exception e) { Test.sendStacktrace(e); System.out.println("signature wrong, data could not be displayed, exception thrown"); } PreparedStatement stmt2 = connection.prepareStatement("delete FROM message WHERE message_id = ?"); stmt2.setInt(1, message_id); stmt2.executeUpdate(); stmt2.close(); Test.messageStore.resetMessageCounter(); Log.put("deleted a message from DB since its verification failed...", -20); } } catch (SQLException ex) { Logger.getLogger(MessageVerifierHsqlDb.class.getName()).log(Level.SEVERE, null, ex); } //if (sem.availablePermits() < MAX_PERMITS) { sem.release(); Log.put("Available permits after release: " + sem.availablePermits(), 20); //} } catch (Throwable e) { e.printStackTrace(); Test.sendStacktrace(e); } } }; threadPool.submit(runnable); Log.put("Available permits: " + sem.availablePermits(), 20); sem.acquireUninterruptibly(); } //wait for all to finish sem.acquireUninterruptibly(MAX_PERMITS); sem.release(MAX_PERMITS); breaked = interrupted(); if (cnt == loadMsgsPerQuery) { breaked = true; } else { MessageDownloader.publicMsgsLoadedLock.lock(); MessageDownloader.publicMsgsLoaded = 0; MessageDownloader.publicMsgsLoadedLock.unlock(); } executeQuery.close(); try { if (breaked) { sleep(20); } else { sleep(1000 * 60 * 5); } } catch (InterruptedException ex) { } } catch (org.hsqldb.HsqlException ex) { System.out.println("HSQL DB exception, not that problem here"); } catch (java.sql.SQLTransactionRollbackException ex) { System.out.println("transaction rollback exception, not that problem here, sleep 10 second"); try { sleep(11375); } catch (InterruptedException ex1) { } } catch (Throwable ex) { try { sleep(1000); } catch (InterruptedException ex1) { } // if (ex instanceof SQLNonTransientConnectionException) { // if (!Main.shutdown) { // if (System.currentTimeMillis() - lastDbReconnected > 1000 * 60 * 5) { // System.out.println("################################\n# reconnect db\n################################"); // Test.hsqlConnection.reconnect(); // lastDbReconnected = System.currentTimeMillis(); // } // } // } if (ex instanceof java.sql.SQLTransactionRollbackException) { System.out.println("LOCK PROBLEM - but that may not cause any problems here."); ex.printStackTrace(); } Logger.getLogger(MessageVerifierHsqlDb.class.getName()).log(Level.SEVERE, null, ex); if (ex instanceof NullPointerException) { Test.sendStacktrace(ex); System.out.println("RESTART, nullpointer in verifier!"); System.exit(0); } if (ex instanceof SQLIntegrityConstraintViolationException) { System.out.println("#############################Please remove database files!!!!#######################"); System.out.println("Please remove database files!!!!"); System.out.println("Please remove database files!!!!"); System.out.println("Please remove database files!!!!"); System.out.println("SYSTEM EXIT"); System.exit(0); } else { //Test.sendStacktrace(ex); } } } } /** * this method checks if the channel is writeable or not * * @param message */ private void sendDeliveredMessage(final RawMsg message) { if (!message.getChannel().isWriteable()) { return; } sendDeliveredMsgsThreads.submit(new Runnable() { @Override public void run() { DeliveredMsg build = DeliveredMsg.build(message.getChannel(), message.public_type, message.timestamp, message.nonce); RawMsg addMessage = MessageHolder.addMessage(build); Test.broadcastMsg(addMessage); } }); } } public static String formatTime(Date date) { String hours = "" + date.getHours(); String minutes = "" + date.getMinutes(); String seconds = "" + date.getSeconds(); if (hours.length() == 1) { hours = "0" + hours; } if (minutes.length() == 1) { minutes = "0" + minutes; } if (seconds.length() == 1) { seconds = "0" + seconds; } return hours + ":" + minutes + ":" + seconds; } public static void writeBytesToFile(byte[] b, String path) { File file = new File(path); try { FileOutputStream fileOutputStream = new FileOutputStream(file); try { fileOutputStream.write(b); } catch (IOException ex) { Logger.getLogger(ImageSaver.class.getName()).log(Level.SEVERE, null, ex); } finally { try { fileOutputStream.close(); } catch (IOException ex) { Logger.getLogger(MessageVerifierHsqlDb.class.getName()).log(Level.SEVERE, null, ex); } } } catch (FileNotFoundException ex) { Logger.getLogger(ImageSaver.class.getName()).log(Level.SEVERE, null, ex); } } public static void printStack() { StackTraceElement[] stackTrace = MessageVerifierHsqlDb.myThread.getStackTrace(); String ownStackTrace = ""; for (StackTraceElement a : stackTrace) { ownStackTrace += a.toString() + "\n"; } System.out.println("MessageVerifierHsqlDb:" + ownStackTrace); } private static HashAndCount generateMyHashAndMsgCount(BlockMsg blockMsg) throws SQLException { //get Key Id //String query = "SELECT pubkey_id,message_id,content,public_type,timestamp,nonce from message WHERE timestamp > ? and verified = true AND pubkey_id = ?"; String query = "SELECT timestamp,message_type,public_type from channelmessage WHERE pubkey_id =? AND timestamp > ? AND timestamp < ? ORDER BY timestamp ASC"; PreparedStatement pstmt = Test.messageStore.getConnection().prepareStatement(query); pstmt.setInt(1, blockMsg.channel.getKey().database_id); long asd = blockMsg.timestamp - BlockMsg.TIME_TO_SYNC_BACK; System.out.println("time: " + asd); pstmt.setLong(2, asd); pstmt.setLong(3, blockMsg.timestamp); ResultSet executeQuery = pstmt.executeQuery(); int msgcount = 0; boolean breaked = false; byte[] dataArray = new byte[1024 * 200]; ByteBuffer buffer = ByteBuffer.wrap(dataArray); //max size of a message!! should be regulated later! //ToDo: add hash from all data and count of messages to get an easier sync! //System.out.println("dwzdzwd " + executeQuery.next()); while (executeQuery.next()) { int message_type = executeQuery.getInt("message_type"); long timestamp = executeQuery.getLong("timestamp"); byte public_type = executeQuery.getByte("public_type"); //only pack a message into a block if the public_type is 20! if (public_type == 20) { //skip content which will be generated regulary, image messages should not have public_type 20! (with new version, old imgs will be deleted) if (message_type != TextMsg.BYTE) { continue; } if (buffer.remaining() < 8 + 4 + 4) { System.out.println("buffer full, exit routine, dont know what to do atm"); breaked = true; return null; } //System.out.println("Data: msgtyp: " + message_type + " pubtyp: " + public_type); buffer.putLong(timestamp); buffer.putInt(message_type); buffer.putInt(public_type); msgcount++; } } executeQuery.close(); pstmt.close(); if (breaked) { System.out.println("abort..."); return null; } //generated msgcount and hash: int hash = Sha256Hash.create(dataArray).hashCode(); return new HashAndCount(msgcount, hash); } private static class HashAndCount { int cnt; int hash; public HashAndCount(int cnt, int hash) { this.cnt = cnt; this.hash = hash; } } }