Files
KLALB/src/org/kne/cloud/network/frpc/FrpcProcess.java
T

274 lines
7.0 KiB
Java

package org.kne.cloud.network.frpc;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.ProcessHandle.Info;
import java.net.BindException;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
public class FrpcProcess extends Process{
private static File defaultBase=new File("frpc");
private volatile Thread hook;
public static File getDefaultBase() {
return defaultBase;
}
public static void setDefaultBase(File defaultBase) {
FrpcProcess.defaultBase = defaultBase;
}
private File base;
private File exe;
private Process theProcess;
private File config_file;
public FrpcProcess(String ini) throws IOException {
this(defaultBase,ini);
}
public FrpcProcess(File base,String ini) throws IOException {
this.base=base;
if(System.getProperty("os.name").toLowerCase().contains("windows")) {
exe=new File(base,"frpc_windows_amd64.exe");
}else {
exe=new File(base,"frpc_linux_amd64");
}
AtomicReference<IOException >arex=new AtomicReference<IOException >();
synchronized (getClass()) {
UUID uid=UUID.randomUUID();
config_file = new File(base,"frpc_conf_"+uid+".ini");
config_file.createNewFile();
config_file.deleteOnExit();
PrintWriter ps=null;
try {
ps=new PrintWriter(config_file);
ps.println(ini);
}finally {
if(ps!=null)
ps.close();
}
List<String>lstc=new ArrayList<>();
lstc.add(exe.getAbsolutePath());
lstc.add("-c");
lstc.add(config_file.getName());
ProcessBuilder psb=new ProcessBuilder(lstc);
psb.directory(base);
theProcess=psb.start();
Thread t=Thread.currentThread();
hook=new Thread(()->{
try {
hook=null;
finalize();
} catch (Throwable e) {
e.printStackTrace();
}
});
Runtime.getRuntime().addShutdownHook(hook);
CountDownLatch cdl=new CountDownLatch(1);
new Thread(()->{
BufferedReader br=new BufferedReader(new InputStreamReader(theProcess.getInputStream()));
try {
while(true) {
String s=br.readLine();
if(s==null) {
break;
}
cdl.countDown();
System.out.println ("{"+uid+"}"+s);
if(s.contains("start proxy success")) {
t.interrupt();
}else if(s.contains("port already used")){
arex.set(new BindException("port on server already used"));
t.interrupt();
}else if(s.contains("远程端口已经在使用了")) {
arex.set(new BindException("port on server already used"));
t.interrupt();
}else if(s.contains("no such host")) {
arex.set(new UnknownHostException("no such host"));
t.interrupt();
}else if(s.contains("connection write timeout")) {
arex.set(new ConnectException("connection write timeout"));
t.interrupt();
}else if(s.contains("already exists")&&s.contains("proxy")) {
arex.set(new BindException("proxy already exists"));
t.interrupt();
}else if(s.contains("已经存在, 请检查是否重复开启")&&s.contains("隧道")) {
arex.set(new BindException("proxy already exists"));
t.interrupt();
}
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
try {
cdl.await(5000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
if(theProcess.waitFor(20000, TimeUnit.MILLISECONDS)) {
destroy();
throw new SocketException("Frpc exit code:"+theProcess.exitValue());
}else {
destroy();
throw new SocketException("Frpc timed out");
}
} catch (InterruptedException e) {
//destroy();
Thread.interrupted();
if(arex.get()!=null) {
destroy();
arex.get().fillInStackTrace();
throw arex.get();
}
}
}
public File getBase() {
return base;
}
@Override
public OutputStream getOutputStream() {
return theProcess.getOutputStream();
}
@Override
public InputStream getInputStream() {
return theProcess.getInputStream();
}
@Override
public InputStream getErrorStream() {
return theProcess.getErrorStream();
}
@Override
public int waitFor() throws InterruptedException {
return theProcess.waitFor();
}
@Override
public int exitValue() {
return theProcess.exitValue();
}
@Override
public void destroy() {
theProcess.destroy();
//System.out.println("frpc已关闭");
if(hook!=null) {
Runtime.getRuntime().removeShutdownHook(hook);
}
if(config_file!=null) {
config_file.delete();
}
}
@Override
public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException {
return theProcess.waitFor(timeout, unit);
}
@Override
public Process destroyForcibly() {
Process b= theProcess.destroyForcibly();
//System.out.println("frpc已关闭");
if(hook!=null) {
Runtime.getRuntime().removeShutdownHook(hook);
}
return b;
}
@Override
public boolean supportsNormalTermination() {
return theProcess.supportsNormalTermination();
}
@Override
public boolean isAlive() {
return theProcess.isAlive();
}
@Override
public long pid() {
return theProcess.pid();
}
@Override
public CompletableFuture<Process> onExit() {
return theProcess.onExit();
}
@Override
public ProcessHandle toHandle() {
return theProcess.toHandle();
}
@Override
public Info info() {
return theProcess.info();
}
@Override
public Stream<ProcessHandle> children() {
return theProcess.children();
}
@Override
public Stream<ProcessHandle> descendants() {
return theProcess.descendants();
}
public static void main(String[] args) throws IOException {
String str="""
[common]
server_addr = us.afrps.cn
server_port = 7000
token = afrps.cn
protocol=kcp
[test5]
type = tcp
local_ip = 127.0.0.1
local_port = 7461
remote_port = 49966
use_encryption = true
use_compression = true
""";
FrpcIni fi=new FrpcIni(str);
str=fi.storeToString();
//System.out.println(fi.getServerPort());
FrpcProcess fp=new FrpcProcess(str);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected void finalize() throws Throwable {
if(theProcess!=null) {
destroy();
}
}
}