Skip to content

Commit

Permalink
1. Support proxy type: Sock5, HTTP (experimental)
Browse files Browse the repository at this point in the history
2. Improve socket performance
3. Add UI
  • Loading branch information
dashsp committed Dec 23, 2015
1 parent 0defec7 commit 602d603
Show file tree
Hide file tree
Showing 32 changed files with 1,470 additions and 284 deletions.
3 changes: 2 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.stfl</groupId>
<artifactId>shadowsocks-java</artifactId>
<version>0.1-SNAPSHOT</version>
<version>0.2-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand All @@ -17,6 +17,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/stfl/Constant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.stfl;

import java.util.Locale;

public class Constant {
public static final String PROG_NAME = "shadowsocks-java";
public static final String VERSION = "0.2";
public static final int BUFFER_SIZE = 16384;
public static final String CONF_FILE = "config.json";
public static final Locale LOCALE = Locale.getDefault();
}
41 changes: 23 additions & 18 deletions src/main/java/com/stfl/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,28 @@
import com.stfl.misc.Util;
import com.stfl.network.LocalServer;
import com.stfl.network.NioLocalServer;
import com.stfl.network.proxy.IProxy;
import com.stfl.network.proxy.ProxyFactory;
import com.stfl.ss.CryptFactory;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Logger;

public class Main {
private static Logger logger = Logger.getLogger(Main.class.getName());

public static void main(String[] args) {
Logger logger = Logger.getLogger(Main.class.getName());
if (args.length != 0) {
startCommandLine(args);
}
else {
MainGui.launch(MainGui.class);
}
}

private static void startCommandLine(String[] args) {
Config config;

config = parseArgument(args);
Expand All @@ -26,26 +34,16 @@ public static void main(String[] args) {
return;
}

String s = config.saveToJson();
PrintWriter writer = null;
try {
writer = new PrintWriter("config.json");
writer.println(s);
writer.close();
} catch (FileNotFoundException e) {
logger.warning("Unable to save config");
}
Util.saveFile(Constant.CONF_FILE, config.saveToJson());

try {
//LocalServer server = new LocalServer(config);
NioLocalServer server = new NioLocalServer(config);
Thread t = new Thread(server);
t.start();
logger.info("Shadowsocks-Java v" + Util.getVersion());
logger.info("Server starts at port: " + config.getLocalPort());
t.join();
} catch (Exception e) {
e.printStackTrace();
logger.warning("Unable to start server: " + e.toString());
}
}

Expand Down Expand Up @@ -100,6 +98,9 @@ else if (args[i].equals("--cipher")) {
else if (args[i].equals("--password")) {
config.setPassword(args[i + 1]);
}
else if (args[i].equals("--proxy")) {
config.setProxyType(args[i + 1]);
}
}

return config;
Expand All @@ -113,13 +114,17 @@ private static void printUsage() {
System.out.println(" --cipher [CIPHER_NAME]");
System.out.println(" --password [PASSWORD]");
System.out.println(" --config [CONFIG_FILE]");
System.out.println(" --proxy [TYPE]");
System.out.println("Support Proxy Type:");
for (IProxy.TYPE t : ProxyFactory.getSupportedProxyTypes()) {
System.out.printf(" %s\n", t.toString().toLowerCase());
}
System.out.println("Support Ciphers:");
for (String s : CryptFactory.getSupportedCiphers()) {
System.out.printf(" %s\n", s);
}
System.out.println("Example:");
System.out.println(" ss --local \"127.0.0.1:1080\" --remote \"[SS_SERVER_IP]:8080\" --cipher \"aes-256-cfb\" --password \"HelloWorld\"");
System.out.println(" ss --local \"127.0.0.1:1080\" --remote \"[SS_SERVER_IP]:1080\" --cipher \"aes-256-cfb\" --password \"HelloWorld\"");
System.out.println(" ss --config config.json");

}
}
143 changes: 143 additions & 0 deletions src/main/java/com/stfl/MainGui.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package com.stfl;

import com.stfl.misc.UTF8Control;
import com.stfl.ui.MainLayoutController;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.ResourceBundle;
import java.util.logging.Logger;

public class MainGui extends Application {
private static Logger logger = Logger.getLogger(MainGui.class.getName());
private Stage primaryStage;
private Scene rootScene;
private MainLayoutController controller;
private TrayIcon trayIcon;

@Override
public void start(Stage primaryStage) throws Exception {

Platform.setImplicitExit(false);
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Server Configuration");

try {
// Load the root layout from the fxml file
FXMLLoader mainLayoutLoader = new FXMLLoader(MainGui.class.getResource("/resources/ui/MainLayout.fxml"));
mainLayoutLoader.setResources(ResourceBundle.getBundle("resources.bundle.ui", Constant.LOCALE, new UTF8Control()));
Pane rootLayout = mainLayoutLoader.load();

rootScene = new Scene(rootLayout);
primaryStage.setScene(rootScene);
primaryStage.setResizable(false);

controller = mainLayoutLoader.getController();
controller.setMainGui(this);

addToTray();

primaryStage.getIcons().add(new Image(MainGui.class.getResource("/resources/image/icon.png").toString()));
primaryStage.show();
} catch (IOException e) {
// Exception gets thrown if the fxml file could not be loaded
e.printStackTrace();
}
}


private void addToTray() {
// ensure awt is initialized
java.awt.Toolkit.getDefaultToolkit();

// make sure system tray is supported
if (!java.awt.SystemTray.isSupported()) {
logger.warning("No system tray support!");
}

final java.awt.SystemTray tray = java.awt.SystemTray.getSystemTray();
try {

java.awt.Image image = ImageIO.read(MainGui.class.getResource("/resources/image/icon.png"));
trayIcon = new TrayIcon(image);
trayIcon.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Platform.runLater(new Runnable() {
@Override
public void run() {
primaryStage.show();
}
});
}
});

java.awt.MenuItem openItem = new java.awt.MenuItem("Configuration");
openItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Platform.runLater(new Runnable() {
@Override
public void run() {
show();
}
});
}
});

java.awt.MenuItem exitItem = new java.awt.MenuItem("Exit");
exitItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
controller.closeServer();
Platform.exit();
tray.remove(trayIcon);
}
});

PopupMenu popup = new PopupMenu();
popup.add(openItem);
popup.addSeparator();
popup.add(exitItem);
trayIcon.setPopupMenu(popup);
trayIcon.setToolTip("Not Connected");
tray.add(trayIcon);
} catch (IOException e) {
e.printStackTrace();
} catch (AWTException e) {
e.printStackTrace();
}
}

public void show() {
primaryStage.show();
}

public void hide() {
primaryStage.hide();
}

public void setTooltip(String message) {
if (trayIcon != null) {
trayIcon.setToolTip(message);
}
}

public void showNotification(String message) {
trayIcon.displayMessage(
"shadowsocks-java",
message,
java.awt.TrayIcon.MessageType.INFO
);
}
}
43 changes: 30 additions & 13 deletions src/main/java/com/stfl/misc/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

package com.stfl.misc;

import com.stfl.network.proxy.IProxy;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import com.stfl.ss.AesCrypt;
Expand All @@ -46,10 +47,10 @@ public class Config {
private String _method;
private String _password;
private String _logLevel;
private boolean _isSock5Server;
private IProxy.TYPE _proxyType;

public Config() {
load();
loadFromJson("");
}

public Config(String ipAddr, int port, String localIpAddr, int localPort, String method, String password) {
Expand All @@ -60,6 +61,12 @@ public Config(String ipAddr, int port, String localIpAddr, int localPort, String
_localPort = localPort;
_method = method;
_password = password;
_proxyType = IProxy.TYPE.AUTO;
}

public Config(String ipAddr, int port, String localIpAddr, int localPort, String method, String password, IProxy.TYPE type) {
this(ipAddr, port, localIpAddr, localPort, method, password);
_proxyType = type;
}

public void setRemoteIpAddress(String value) {
Expand Down Expand Up @@ -94,12 +101,21 @@ public int getLocalPort() {
return _localPort;
}

public void setSocks5Server(boolean value) {
_isSock5Server =value;
public void setProxyType(String value) {
_proxyType = IProxy.TYPE.AUTO;
if (value.toLowerCase().equals(IProxy.TYPE.HTTP.toString().toLowerCase())) {
_proxyType = IProxy.TYPE.HTTP;
}
else if (value.toLowerCase().equals(IProxy.TYPE.SOCKS5.toString().toLowerCase())) {
_proxyType = IProxy.TYPE.SOCKS5;
}
}

public boolean isSock5Server() {
return _isSock5Server;
public void setProxyType(IProxy.TYPE value) {
_proxyType = value;
}
public IProxy.TYPE getProxyType() {
return _proxyType;
}

public void setMethod(String value) {
Expand Down Expand Up @@ -127,20 +143,20 @@ public String getLogLevel() {
return _logLevel;
}

public void load() {
loadFromJson("{}");
}

public void loadFromJson(String jsonStr) {
if (jsonStr.length() == 0) {
jsonStr = "{}";
}

JSONObject jObj = (JSONObject)JSONValue.parse(jsonStr);
_ipAddr = (String)jObj.getOrDefault("remoteIpAddress", "");
_port = ((Number)jObj.getOrDefault("remotePort", 1080)).intValue();
_localIpAddr = (String)jObj.getOrDefault("localIpAddress", "127.0.0.1");
_localPort = ((Number)jObj.getOrDefault("localPort", 1082)).intValue();
_localPort = ((Number)jObj.getOrDefault("localPort", 1080)).intValue();
_method = (String)jObj.getOrDefault("method", AesCrypt.CIPHER_AES_256_CFB);
_password = (String)jObj.getOrDefault("password", "");
_logLevel = (String)jObj.getOrDefault("logLevel", "INFO");
_isSock5Server = (Boolean) jObj.getOrDefault("isSocks5Server", true);
setProxyType((String) jObj.getOrDefault("proxyType", IProxy.TYPE.SOCKS5.toString().toLowerCase()));
setLogLevel(_logLevel);
}

Expand All @@ -152,7 +168,8 @@ public String saveToJson() {
jObj.put("localPort", _localPort);
jObj.put("method", _method);
jObj.put("password", _password);
jObj.put("isSocks5Server", _isSock5Server);
jObj.put("proxyType", _proxyType.toString().toLowerCase());
jObj.put("logLevel", _logLevel);

return Util.prettyPrintJson(jObj);
}
Expand Down
Loading

0 comments on commit 602d603

Please sign in to comment.