import javax.imageio.*; import java.awt.image.*; import java.awt.event.*; import java.awt.*; import java.security.NoSuchAlgorithmException; import java.security.MessageDigest; import java.lang.management.*; import java.lang.reflect.*; import java.net.*; import java.io.*; import javax.swing.text.*; import javax.swing.event.*; import javax.swing.*; import java.util.concurrent.atomic.*; import java.util.concurrent.*; import java.util.regex.*; import java.util.List; import java.util.zip.*; import java.util.*; public class main { static long hours = 24; public static void main(String[] args) throws Exception { print("Periodic rebooter. Sleeping till reboot time."); // TODO: print that time sleepSeconds(60*60*hours); startBot("Reboot Bot", "#1001218"); sendToLocalBot("Reboot Bot", "please reboot the machine."); } static void startBot(String botName, String scriptID) { DialogIO bot = findBot(botName); if (bot != null) bot.close(); else { print("Bot " + quote(botName) + " not found. Starting " + scriptID); nohupJavax(scriptID); waitForBotStartUp(botName); } } static String sendToLocalBot(String bot, String text) { try { DialogIO channel = findBot(bot); if (channel == null) { fail(quote(bot) + " not found"); } channel.readLine(); print(bot + "> " + text); channel.sendLine(text); String s = channel.readLine(); print(bot + "< " + s); channel.close(); return s; } catch (Throwable e) { e.printStackTrace(); return null; } } static String sendToLocalBot(int port, String text) { try { DialogIO channel = talkTo(port); channel.readLine(); print(port + "> " + text); channel.sendLine(text); String s = channel.readLine(); print(port + "< " + s); channel.close(); return s; } catch (Throwable e) { e.printStackTrace(); return null; } } static void sleepSeconds(long s) { if (s > 0) sleep(s*1000); } static void print() { System.out.println(); } static void print(Object o) { System.out.println(o); } static void print(long i) { System.out.println(i); } static long waitForBotStartUp_timeoutSeconds = 60; static void waitForBotStartUp(String botName) { for (int i = 0; i < waitForBotStartUp_timeoutSeconds; i++) { sleepSeconds(i == 0 ? 0 : 1); DialogIO bot = findBot(botName); if (bot != null) { bot.close(); return; } } fail("Bot not found: " + quote(botName)); } static String quote(String s) { if (s == null) return "null"; return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\r", "\\r").replace("\n", "\\n") + "\""; } static String quote(long l) { return quote("" + l); } static Map findBot_cache = new TreeMap(); static int findBot_timeout = 5000; static DialogIO findBot(String searchPattern) { Integer port = findBot_cache.get(searchPattern); if (port != null) try { DialogIO io = talkTo("localhost", port); io.waitForLine(/*findBot_timeout*/); // TODO: implement String line = io.readLineNoBlock(); if (indexOfIgnoreCase(line, searchPattern) == 0) { call(io, "pushback", line); // put hello string back in return io; } } catch (Exception e) { e.printStackTrace(); } for (ProgramScan.Program p : quickBotScan()) if (indexOfIgnoreCase(p.helloString, searchPattern) == 0) { // strict matching - start of hello string only, but case-insensitive findBot_cache.put(searchPattern, p.port); return talkTo("localhost", p.port); } return null; } static abstract class DialogIO { abstract boolean isStillConnected(); abstract String readLineNoBlock(); abstract boolean waitForLine(); abstract void sendLine(String line); abstract boolean isLocalConnection(); abstract Socket getSocket(); abstract void close(); String readLine() { waitForLine(); return readLineNoBlock(); } } static abstract class DialogHandler { abstract void run(DialogIO io); } // DialogIO static DialogIO talkTo(int port) { return talkTo("localhost", port); } static DialogIO talkTo(String ip, int port) { try { print("Talking to " + ip + ":" + port); final Socket s = new Socket(ip, port); final Writer w = new OutputStreamWriter(s.getOutputStream(), "UTF-8"); final BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8")); return new DialogIO() { String line; boolean buff; boolean isLocalConnection() { return s.getInetAddress().isLoopbackAddress(); } boolean isStillConnected() { return !(buff || s.isClosed()); } String readLineNoBlock() { String l = line; line = null; return l; } boolean waitForLine() { try { if (line != null) return true; //print("Readline"); line = in.readLine(); //print("Readline done: " + line); if (line == null) buff = true; return line != null; } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} void sendLine(String line) { try { w.write(line + "\n"); w.flush(); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} void close() { try { s.close(); } catch (IOException e) { // whatever } } Socket getSocket() { return s; } void pushback(String l) { if (line != null) fail(); line = l; } }; } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static void nohupJavax(String javaxargs) { try { int x = latestInstalledJavaX(); File xfile = new File(userHome(), ".javax/x" + Math.max(x, 26) + ".jar"); if (!xfile.isFile()) { String url = "http://tinybrain.de/x26.jar"; byte[] data = loadBinaryPage(url); if (data.length < 1000000) fail("Could not load " + url); saveBinaryFile(xfile.getPath(), data); } String jarPath = xfile.getPath(); if (javaxargs.startsWith("#")) javaxargs = javaxargs.substring(1); nohup("java -jar " + (isWindows() ? winQuote(jarPath) : bashQuote(jarPath)) + " " + javaxargs); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static void sleep(long ms) { try { Thread.sleep(ms); } catch (Exception e) { throw new RuntimeException(e); } } static void sleep() { try { synchronized(main.class) { main.class.wait(); } } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static RuntimeException fail() { throw new RuntimeException("fail"); } static RuntimeException fail(Object msg) { throw new RuntimeException(String.valueOf(msg)); } static int latestInstalledJavaX() { File[] files = new File(userHome(), ".javax").listFiles(); int v = 0; if (files != null) for (File f : files) { Matcher m = Pattern.compile("x(\\d\\d\\d?)\\.jar").matcher(f.getName()); if (m.matches()) v = Math.max(v, Integer.parseInt(m.group(1))); } return v; } static class ProgramScan { static int threads = isWindows() ? 500 : 10; static int timeout = 5000; // hmm... static String ip = "127.0.0.1"; static int quickScanFrom = 10000, quickScanTo = 10999; static class Program { int port; String helloString; Program(int port, String helloString) { this.helloString = helloString; this.port = port;} } static List scan() { try { return scan(1, 65535); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static List scan(int fromPort, int toPort) { return scan(fromPort, toPort, new int[0]); } static List scan(int fromPort, int toPort, int[] preferredPorts) { try { Set preferredPortsSet = new HashSet(asList(preferredPorts)); String name = toPort < 10000 ? "bot" : "program"; final ExecutorService es = Executors.newFixedThreadPool(threads); print(firstToUpper(name) + "-scanning " + ip + " with timeout " + timeout + " ms in " + threads + " threads."); startTiming(); List> futures = new ArrayList>(); for (int port : preferredPorts) futures.add(checkPort(es, ip, port, timeout)); for (int port = fromPort; port <= toPort; port++) if (!preferredPortsSet.contains(port)) futures.add(checkPort(es, ip, port, timeout)); es.shutdown(); List programs = new ArrayList(); for (final Future f : futures) { Program p = f.get(); if (p != null) programs.add(p); } stopTiming(); print("Found " + programs.size() + " " + name + "(s) on " + ip); return programs; } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static Future checkPort(final ExecutorService es, final String ip, final int port, final int timeout) { return es.submit(new Callable() { @Override public Program call() { try { Socket socket = new Socket(); socket.setSoTimeout(timeout); socket.connect(new InetSocketAddress(ip, port), timeout); print("Connected to " + ip + ":" + port); BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream(), "UTF-8")); String hello = in.readLine(); socket.close(); return new Program(port, hello); } catch (Exception ex) { return null; } } }); } static List quickScan() { return scan(quickScanFrom, quickScanTo); } static List quickBotScan() { return quickBotScan(new int[0]); } static List quickBotScan(int[] preferredPorts) { return scan(5000, 5999, preferredPorts); } } // ProgramScan static List quickBotScan() { return ProgramScan.quickBotScan(); } static List quickBotScan(int[] preferredPorts) { return ProgramScan.quickBotScan(preferredPorts); } /** possibly improvable */ public static String bashQuote(String text) { if (text == null) return null; return "\"" + text .replace("\\", "\\\\") .replace("\"", "\\\"") .replace("\n", "\\n") .replace("\r", "\\r") + "\""; } /** possibly improvable */ public static String winQuote(String text) { if (text == null) return null; return "\"" + text .replace("\\", "\\\\") .replace("\"", "\\\"") .replace("\n", "\\n") .replace("\r", "\\r") + "\""; } public static boolean isWindows() { return System.getProperty("os.name").contains("Windows"); } public static File nohup(String cmd) throws IOException { File outFile = File.createTempFile("nohup_" + nohup_sanitize(cmd), ".out"); nohup(cmd, outFile, false); return outFile; } static String nohup_sanitize(String s) { return s.replaceAll("[^a-zA-Z0-9\\-_]", ""); } /** outFile takes stdout and stderr. */ public static void nohup(String cmd, File outFile, boolean append) throws IOException { String command = nohup_makeNohupCommand(cmd, outFile, append); File scriptFile = File.createTempFile("_realnohup", isWindows() ? ".bat" : ""); System.out.println("[Nohup] " + command); try { //System.out.println("[RealNohup] Script file: " + scriptFile.getPath()); saveTextFile(scriptFile.getPath(), command); String[] command2; if (isWindows()) command2 = new String[] {"cmd", "/c", "start", "/b", scriptFile.getPath() }; else command2 = new String[] {"/bin/bash", scriptFile.getPath() }; Process process = Runtime.getRuntime().exec(command2); try { process.waitFor(); } catch (InterruptedException e) { throw new RuntimeException(e); } int value = process.exitValue(); //System.out.println("exit value: " + value); } finally { if (!isWindows()) scriptFile.delete(); } } public static String nohup_makeNohupCommand(String cmd, File outFile, boolean append) { mkdirsForFile(outFile); String command; if (isWindows()) command = cmd + (append ? " >>" : " >") + winQuote(outFile.getPath()) + " 2>&1"; else command = "nohup " + cmd + (append ? " >>" : " >") + bashQuote(outFile.getPath()) + " 2>&1 &"; return command; } static byte[] loadBinaryPage(String url) throws IOException { return loadBinaryPage(new URL(url).openConnection()); } public static byte[] loadBinaryPage(URLConnection con) throws IOException { //setHeaders(con); ByteArrayOutputStream buf = new ByteArrayOutputStream(); InputStream inputStream = con.getInputStream(); int n = 0; while (true) { int ch = inputStream.read(); if (ch < 0) break; buf.write(ch); if (++n % 100000 == 0) System.err.println(" " + n + " bytes loaded."); } inputStream.close(); return buf.toByteArray(); } /** writes safely (to temp file, then rename) */ public static void saveBinaryFile(String fileName, byte[] contents) throws IOException { File file = new File(fileName); File parentFile = file.getParentFile(); if (parentFile != null) parentFile.mkdirs(); String tempFileName = fileName + "_temp"; FileOutputStream fileOutputStream = new FileOutputStream(tempFileName); fileOutputStream.write(contents); fileOutputStream.close(); if (file.exists() && !file.delete()) throw new IOException("Can't delete " + fileName); if (!new File(tempFileName).renameTo(file)) throw new IOException("Can't rename " + tempFileName + " to " + fileName); } static void saveBinaryFile(File fileName, byte[] contents) { try { saveBinaryFile(fileName.getPath(), contents); } catch (IOException e) { throw new RuntimeException(e); } } static Object call(Object o, String method, Object... args) { try { if (o instanceof Class) { Method m = call_findStaticMethod((Class) o, method, args, false); m.setAccessible(true); return m.invoke(null, args); } else { Method m = call_findMethod(o, method, args, false); m.setAccessible(true); return m.invoke(o, args); } } catch (Exception e) { throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e); } } static Method call_findStaticMethod(Class c, String method, Object[] args, boolean debug) { Class _c = c; while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (!m.getName().equals(method)) { if (debug) System.out.println("Method name mismatch: " + method); continue; } if ((m.getModifiers() & Modifier.STATIC) == 0 || !call_checkArgs(m, args, debug)) continue; return m; } c = c.getSuperclass(); } throw new RuntimeException("Method '" + method + "' (static) with " + args.length + " parameter(s) not found in " + _c.getName()); } static Method call_findMethod(Object o, String method, Object[] args, boolean debug) { Class c = o.getClass(); while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (m.getName().equals(method) && call_checkArgs(m, args, debug)) return m; } c = c.getSuperclass(); } throw new RuntimeException("Method '" + method + "' (non-static) with " + args.length + " parameter(s) not found in " + o.getClass().getName()); } private static boolean call_checkArgs(Method m, Object[] args, boolean debug) { Class[] types = m.getParameterTypes(); if (types.length != args.length) { if (debug) System.out.println("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) { if (debug) System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); return false; } return true; } static String _userHome; static String userHome() { if (_userHome == null) { if (isAndroid()) _userHome = "/storage/sdcard0/"; else _userHome = System.getProperty("user.home"); //System.out.println("userHome: " + _userHome); } return _userHome; } // works on lists and strings and null static int indexOfIgnoreCase(Object a, Object b) { if (a == null) return -1; if (a instanceof String) { Matcher m = Pattern.compile((String) b, Pattern.CASE_INSENSITIVE + Pattern.LITERAL).matcher((String) a); if (m.find()) return m.start(); else return -1; } if (a instanceof List) { for (int i = 0; i < ((List) a).size(); i++) { Object o = ((List) a).get(i); if (o != null && ((String) o).equalsIgnoreCase((String) b)) return i; } return -1; } throw fail("Unknown type: " + a); } // extended over Class.isInstance() to handle primitive types static boolean isInstanceX(Class type, Object arg) { if (type == boolean.class) return arg instanceof Boolean; if (type == int.class) return arg instanceof Integer; if (type == long.class) return arg instanceof Long; if (type == float.class) return arg instanceof Float; if (type == short.class) return arg instanceof Short; if (type == char.class) return arg instanceof Character; if (type == byte.class) return arg instanceof Byte; return type.isInstance(arg); } static boolean isAndroid() { return System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0; } public static void mkdirsForFile(File file) { File dir = file.getParentFile(); if (dir != null) // is null if file is in current dir dir.mkdirs(); } static Object process(String processorID, Object in) { return process(processorID, in, "in"); } static Object process(String processorID, Object in, String outVar) { try { Class processor = hotwire(processorID); set(processor, "in", in); call(processor, "main", new Object[] {new String[0]}); return get(processor, outVar); } catch (Exception e) { throw new RuntimeException("Error in #" + parseSnippetID(processorID), e); } } /** writes safely (to temp file, then rename) */ public static void saveTextFile(String fileName, String contents) throws IOException { File file = new File(fileName); File parentFile = file.getParentFile(); if (parentFile != null) parentFile.mkdirs(); String tempFileName = fileName + "_temp"; if (contents != null) { FileOutputStream fileOutputStream = new FileOutputStream(tempFileName); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8"); PrintWriter printWriter = new PrintWriter(outputStreamWriter); printWriter.print(contents); printWriter.close(); } if (file.exists() && !file.delete()) throw new IOException("Can't delete " + fileName); if (contents != null) if (!new File(tempFileName).renameTo(file)) throw new IOException("Can't rename " + tempFileName + " to " + fileName); } public static void saveTextFile(File fileName, String contents) { try { saveTextFile(fileName.getPath(), contents); } catch (IOException e) { throw new RuntimeException(e); } } // compile JavaX source, load classes & return main class // src can be a snippet ID or actual source code static Class hotwire(String src) { try { Class j = getJavaX(); List libraries = new ArrayList(); File srcDir = (File) call(j, "transpileMain", src, libraries); if (srcDir == null) fail("transpileMain returned null (src=" + quote(src) + ")"); Object androidContext = get(j, "androidContext"); if (androidContext != null) return (Class) call(j, "loadx2android", srcDir, src); File classesDir = (File) call(j, "TempDirMaker_make"); String javacOutput = (String) call(j, "compileJava", srcDir, libraries, classesDir); System.out.println(javacOutput); URL[] urls = new URL[libraries.size()+1]; urls[0] = classesDir.toURI().toURL(); for (int i = 0; i < libraries.size(); i++) urls[i+1] = libraries.get(i).toURI().toURL(); // make class loader URLClassLoader classLoader = new URLClassLoader(urls); // load & return main class Class theClass = classLoader.loadClass("main"); call(j, "setVars", theClass, isSnippetID(src) ? src: null); return theClass; } catch (Exception e) { throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e); } } static void set(Object o, String field, Object value) { if (o instanceof Class) set((Class) o, field, value); else try { Field f = set_findField(o.getClass(), field); f.setAccessible(true); f.set(o, value); } catch (Exception e) { throw new RuntimeException(e); } } static void set(Class c, String field, Object value) { try { Field f = set_findStaticField(c, field); f.setAccessible(true); f.set(null, value); } catch (Exception e) { throw new RuntimeException(e); } } static Field set_findField(Class c, String field) { for (Field f : c.getDeclaredFields()) if (f.getName().equals(field)) return f; throw new RuntimeException("Field '" + field + "' not found in " + c.getName()); } static Field set_findStaticField(Class c, String field) { for (Field f : c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0) return f; throw new RuntimeException("Static field '" + field + "' not found in " + c.getName()); } static Object get(Object o, String field) { if (o instanceof Class) return get((Class) o, field); try { Field f = get_findField(o.getClass(), field); f.setAccessible(true); return f.get(o); } catch (Exception e) { throw new RuntimeException(e); } } static Object get(Class c, String field) { try { Field f = get_findStaticField(c, field); f.setAccessible(true); return f.get(null); } catch (Exception e) { throw new RuntimeException(e); } } static Field get_findStaticField(Class c, String field) { for (Field f : c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0) return f; throw new RuntimeException("Static field '" + field + "' not found in " + c.getName()); } static Field get_findField(Class c, String field) { for (Field f : c.getDeclaredFields()) if (f.getName().equals(field)) return f; throw new RuntimeException("Field '" + field + "' not found in " + c.getName()); } public static long parseSnippetID(String snippetID) { return Long.parseLong(shortenSnippetID(snippetID)); } static Class __javax; static Class getJavaX() { return __javax; } public static boolean isSnippetID(String s) { try { parseSnippetID(s); return true; } catch (RuntimeException e) { return false; } } static String shortenSnippetID(String snippetID) { if (snippetID.startsWith("#")) snippetID = snippetID.substring(1); String httpBlaBla = "http://tinybrain.de/"; if (snippetID.startsWith(httpBlaBla)) snippetID = snippetID.substring(httpBlaBla.length()); return snippetID; } static String firstToUpper(String s) { if (s.length() == 0) return s; return Character.toUpperCase(s.charAt(0)) + s.substring(1); } static BufferedReader readLine_reader; static String readLine() { try { if (readLine_reader == null) readLine_reader = new BufferedReader(new InputStreamReader(System.in, "UTF-8")); String s = readLine_reader.readLine(); if (s != null) print(s); return s; } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static ArrayList asList(A[] a) { return new ArrayList(Arrays.asList(a)); } static ArrayList asList(int[] a) { ArrayList l = new ArrayList(); for (int i : a) l.add(i); return l; } static ArrayList asList(Set s) { return new ArrayList(s); } static long startTiming_startTime; static void startTiming() { startTiming_startTime = now(); } static void stopTiming() { long end = now(); print("Time: " + (end-startTiming_startTime) + " ms"); } static long now_virtualTime; static long now() { return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis(); } }