LinuxTricks.java

package eu.javaexperience.commands;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import eu.javaexperience.arrays.ArrayTools;
import eu.javaexperience.asserts.AssertArgument;
import eu.javaexperience.collection.CollectionTools;
import eu.javaexperience.io.IOTools;
import eu.javaexperience.process.ProcessTools;
import eu.javaexperience.regex.RegexTools;

public class LinuxTricks
{
	/**
	 * Egy tömböt ad vissza, első indexe 1-1 kapcsolatot jelöl
	 * A második index sorban:<br />
	 * 0 - Távoli Socket cím<br />
	 * 1 - Helyi socket címe<br />
	 * 2 - A kapocsolódott processz pid-je;<br />
	 * 3 - A kapocsolódott processz neve;<br />
	 * 
	 * */
	public static String[][] connmap() throws IOException, InterruptedException
	{
		String res = new String(ProcessTools.processStdoutResult("netstat", "-pnt"));
	
		String[] lines = RegexTools.LINUX_NEW_LINE.split(res);
		String buf[] = null;
		String ki[][] = new String[lines.length-1][3];
		
		for(int i=1;i<lines.length;++i)
		{//3 4 6
			buf = lines[i].split(" {1,}");
			ki[i-1][0] = buf[3];	// program	Socket_addr 
			ki[i-1][1] = buf[4];	// PM/FP 	Socket_addr
			buf = buf[6].split("/");
			ki[i-1][2] = buf[0];	// program pid
		}
		return ki;
	}
	
	public static int processParent(int pid) throws IOException
	{
		//	PPid:	12218
		String mind[] = RegexTools.LINUX_NEW_LINE.split(new String(IOTools.loadFileProcContent("/proc/"+pid+"/status")));
		for(int i=0;i<mind.length;i++)
		{
			if(mind[i].indexOf("PPid:")==0)
			{
				return Integer.parseInt(mind[i].split(" {1,}")[1]);
			}
		}
		return -1;
	}
	
	public static String processCMD(int pid) throws IOException
	{
		return new String(IOTools.loadFileProcContent("/proc/"+pid+"/cmdline"));
	}
	
	public static String localAddress(Socket s)
	{
		return s.getLocalSocketAddress().toString().replaceFirst("/","");	
	}
	
	public static String remote(Socket s)
	{
		return (s.getRemoteSocketAddress().toString().replace("/", ""));
	}
	
	public static String remoteLocal(Socket s)
	{
		return s.getLocalAddress().toString().replace("/", "")+":"+s.getPort();
	}
	
	public static boolean isProcessRunningByPidFile(String pidfile) throws FileNotFoundException, IOException
	{
		if(!new File(pidfile).exists())
		{
			return false;
		}
		
		String pid = IOTools.getFileContents(pidfile).trim();
		
		return new File("/proc/"+pid).exists();
	}
	
	public static int getUnixDomaiSocketPid(String udsFile) throws IOException, InterruptedException
	{
		String res = new String(ProcessTools.processStdoutResult("netstat", "-pnl"));
		
		String[] lines = RegexTools.LINUX_NEW_LINE.split(res);
		
		for(String l:lines)
		{
			String[] cel = RegexTools.SPACES.split(l);
			if(cel.length > 0)
			{
				if("unix".equals(cel[0]))
				{
					for(int i=1;i<cel.length;++i)
					{
						if(cel[i].equals("LISTENING"))
						{
							if(cel[i+3].equals(udsFile))
							{
								return Integer.parseInt(RegexTools.SLASHES.split(cel[i+2])[0]);
							}
						}
					}
				}
			}
		}
		
		return -1;
	}
	
	public static void shutdownProcessGentlyThenHard(int pid, int gently_timeout_ms, int kill_timeout) throws IOException, InterruptedException
	{
		String spid = String.valueOf(pid);
		File exists = new File("/proc/"+spid);
		if(!exists.exists())
		{
			return;
		}
		
		ProcessTools.processStdoutResult("kill", "-2", spid);
		Thread.sleep(gently_timeout_ms);
		if(!exists.exists())
		{
			return;
		}
		
		ProcessTools.processStdoutResult("kill", "-9", spid);
	}
	
	
	public static void startDaemon
	(
		String pidfile,
		String cwd,
		String user,
		String group,
		String executable,
		String... daemon_opts
	)
		throws IOException, InterruptedException
	{
		String[] args = new String[]
		{
			"start-stop-daemon",
			"--start",
			"--quiet",
			"--pidfile",
			pidfile,
			"-d",
			cwd,
			"--chuid",
			user+":"+group,
			"--make-pidfile",
			"--background",
			"--exec",
			executable,
			"--"
		};
		
		ProcessTools.processStderrResult(ArrayTools.arrayConcat(args, daemon_opts));
	}
	
	public static class TraceRouteResult
	{
		public static class TraceRouteHopEntry
		{
			public static class TraceRouteIpEntry
			{
				public final String ip;
				public final double latencyMs;
				
				public TraceRouteIpEntry(String ip, double latencyMs)
				{
					this.ip = ip;
					this.latencyMs = latencyMs;
				}
				
				@Override
				public String toString()
				{
					return "TraceRouteIpEntry: ip: "+ip+", latency: "+latencyMs;
				}
			}
			
			public final int hop;
			public final ArrayList<TraceRouteIpEntry> entries = new ArrayList<>();
			
			public TraceRouteHopEntry(int hop)
			{
				this.hop = hop;
			}
			
			protected static final Pattern PAT = Pattern.compile("^\\s*(?<hop>\\d+)(?<data>[\\s\\.\\dms\\*]+)");
			
			public static TraceRouteHopEntry parseLine(String line)
			{
				Matcher m = PAT.matcher(line);
				if(!m.find())
				{
					return null;
				}
				
				TraceRouteHopEntry ret = new TraceRouteHopEntry(Integer.parseInt(m.group("hop")));
				
				ret.parseEntries(m.group("data").trim());
				
				if(!ret.isUseful())
				{
					return null;
				}
				
				return ret;
			}
			
			protected static final String ip(int index)
			{
				return "(?<ip"+index+">\\d{1,3})";
			}
			
			protected static final Pattern HOSTS = Pattern.compile(ip(0)+"\\."+ip(1)+"\\."+ip(2)+"\\."+ip(3)+"\\s+(?<time>\\d+\\.\\d+)\\s+");
			
			protected void parseEntries(String trim)
			{
				Matcher m = HOSTS.matcher(trim);
				while(m.find())
				{
					String ip = m.group("ip0")+"."+m.group("ip1")+"."+m.group("ip2")+"."+m.group("ip3");
					double latencyMs = Double.parseDouble(m.group("time"));
					TraceRouteIpEntry ent = new TraceRouteIpEntry(ip, latencyMs);
					entries.add(ent);
				}
			}

			public boolean isUseful()
			{
				return !entries.isEmpty();
			}
			
			@Override
			public String toString()
			{
				return "TraceRouteHopEntry: hop: "+hop+", ips: "+CollectionTools.toString(entries);
			}
		}
		
		public final String host;
		public final int maxParallel;
		public final ArrayList<String> resultLines = new ArrayList<>();
		public final ArrayList<TraceRouteHopEntry> hops = new ArrayList<>();
		
		public TraceRouteResult(String host, int maxParallel)
		{
			this.host = host;
			this.maxParallel = maxParallel;
		}

		public static TraceRouteResult parse(String host, int maxParallel, String lines)
		{
			String[] ls = lines.split("\n");
			TraceRouteResult ret = new TraceRouteResult(host, maxParallel);
			CollectionTools.copyInto(ls, ret.resultLines);
			for(String l:ls)
			{
				TraceRouteHopEntry add = TraceRouteHopEntry.parseLine(l);
				if(null != add)
				{
					ret.hops.add(add);
				}
			}
			
			return ret;
		}
		
		@Override
		public String toString()
		{
			return "TraceRouteResult: host: "+host+", maxParallel: "+maxParallel+", hops: "+CollectionTools.toStringMultiline(hops);
		}
	}
	
	public static TraceRouteResult traceroute(String host, int maxParallel) throws IOException, InterruptedException
	{
		AssertArgument.assertGreaterOrEqualsThan(maxParallel, 1, "maxParallel");
		return TraceRouteResult.parse(host, maxParallel, new String(ProcessTools.processStdoutResult("traceroute", "-n", "-w", "3", "-q", String.valueOf(maxParallel), "-N", String.valueOf(maxParallel*90), host)));
	}
	
	public static void main(String[] args) throws IOException, InterruptedException
	{
		System.out.println(traceroute("worldofwarcraft.com", 5));
	}
}