feat: 添加主线程阻断检查

1.修复网络监测
2.修复配置文件错误

Signed-off-by: 502647092 <admin@yumc.pw>
This commit is contained in:
502647092 2016-06-24 18:32:56 +08:00
parent acef319e0d
commit 44842a38ec
8 changed files with 144 additions and 65 deletions

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>pw.yumc</groupId> <groupId>pw.yumc</groupId>
<artifactId>Yum</artifactId> <artifactId>Yum</artifactId>
<version>2.1</version> <version>2.2</version>
<name>Yum</name> <name>Yum</name>
<description>Minecraft 服务器插件管理系统</description> <description>Minecraft 服务器插件管理系统</description>
<build> <build>

View File

@ -3,7 +3,10 @@
*/ */
package pw.yumc.Yum; package pw.yumc.Yum;
import java.util.Timer;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import cn.citycraft.CommonData.UpdatePlugin; import cn.citycraft.CommonData.UpdatePlugin;
@ -17,6 +20,7 @@ import pw.yumc.Yum.listeners.PluginNetworkListener;
import pw.yumc.Yum.listeners.SecurityListener; import pw.yumc.Yum.listeners.SecurityListener;
import pw.yumc.Yum.managers.ConfigManager; import pw.yumc.Yum.managers.ConfigManager;
import pw.yumc.Yum.managers.NetworkManager; import pw.yumc.Yum.managers.NetworkManager;
import pw.yumc.Yum.runnables.MainThreadCheckTask;
/** /**
* MC插件仓库 * MC插件仓库
@ -25,15 +29,50 @@ import pw.yumc.Yum.managers.NetworkManager;
* @since 2015年8月21日下午5:14:39 * @since 2015年8月21日下午5:14:39
*/ */
public class Yum extends JavaPlugin { public class Yum extends JavaPlugin {
NetworkManager netmgr; @Override
public FileConfiguration getConfig() {
return ConfigManager.i().config;
}
public void initCommands() { @Override
public void onDisable() {
NetworkManager.unregister();
}
@Override
public void onEnable() {
new YumAPI(this);
initCommands();
initListeners();
initRunnable();
new VersionChecker(this);
YumAPI.updaterepo(Bukkit.getConsoleSender());
YumAPI.updatecheck(Bukkit.getConsoleSender());
}
@Override
public void onLoad() {
// 初始化配置
ConfigManager.i();
// 初始化更新列
UpdatePlugin.getUpdateList();
// 启用网络注入
NetworkManager.register(this);
}
/**
* 初始化命令
*/
private void initCommands() {
new YumCommand(this); new YumCommand(this);
new NetCommand(this); new NetCommand(this);
new FileCommand(this); new FileCommand(this);
} }
public void initListeners() { /**
* 初始化监听
*/
private void initListeners() {
if (ConfigManager.i().isSetOpEnable()) { if (ConfigManager.i().isSetOpEnable()) {
try { try {
final ClassLoader cl = Class.forName("pw.yumc.injected.event.SetOpEvent").getClassLoader(); final ClassLoader cl = Class.forName("pw.yumc.injected.event.SetOpEvent").getClassLoader();
@ -52,30 +91,15 @@ public class Yum extends JavaPlugin {
new PluginNetworkListener(this); new PluginNetworkListener(this);
PluginKit.scp("§a网络管理系统已启用..."); PluginKit.scp("§a网络管理系统已启用...");
} }
new
} }
@Override /**
public void onDisable() { * 初始化任务
netmgr.unregister(); */
} private void initRunnable() {
final Timer task = new Timer();
@Override PluginKit.scp("§a线程管理系统已启用...");
public void onEnable() { task.scheduleAtFixedRate(new MainThreadCheckTask(Thread.currentThread()), 0, 3000);
new YumAPI(this);
initCommands();
initListeners();
new VersionChecker(this);
YumAPI.updaterepo(Bukkit.getConsoleSender());
YumAPI.updatecheck(Bukkit.getConsoleSender());
}
@Override
public void onLoad() {
// 初始化配置
ConfigManager.i();
// 初始化更新列
UpdatePlugin.getUpdateList();
// 启用网络注入
netmgr = new NetworkManager().register(this);
} }
} }

View File

@ -11,6 +11,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import cn.citycraft.CommonData.UpdatePlugin; import cn.citycraft.CommonData.UpdatePlugin;
import pw.yumc.Yum.managers.ConfigManager;
import pw.yumc.Yum.managers.DownloadManager; import pw.yumc.Yum.managers.DownloadManager;
import pw.yumc.Yum.managers.PluginsManager; import pw.yumc.Yum.managers.PluginsManager;
import pw.yumc.Yum.managers.RepositoryManager; import pw.yumc.Yum.managers.RepositoryManager;
@ -29,20 +30,6 @@ public class YumAPI {
private static RepositoryManager repo; private static RepositoryManager repo;
private static boolean runlock = false; private static boolean runlock = false;
/**
* 初始化Yum管理中心
*
* @param plugin
* 插件实体
*/
public YumAPI(final Plugin plugin) {
YumAPI.main = plugin;
plugman = new PluginsManager(main);
download = new DownloadManager(main);
repo = new RepositoryManager(main);
plugman.addIgnore(main.getConfig().getStringList("ignorelist"));
}
/** /**
* 删除插件 * 删除插件
* *
@ -366,4 +353,18 @@ public class YumAPI {
public static void upgrade(final CommandSender sender, final Plugin plugin) { public static void upgrade(final CommandSender sender, final Plugin plugin) {
plugman.upgrade(sender, plugin); plugman.upgrade(sender, plugin);
} }
/**
* 初始化Yum管理中心
*
* @param plugin
* 插件实体
*/
public YumAPI(final Plugin plugin) {
YumAPI.main = plugin;
plugman = new PluginsManager(main);
download = new DownloadManager(main);
repo = new RepositoryManager(main);
plugman.addIgnore(ConfigManager.i().getIgnoreList());
}
} }

View File

@ -1,32 +1,38 @@
package pw.yumc.Yum.listeners; package pw.yumc.Yum.listeners;
import java.io.IOException;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import cn.citycraft.PluginHelper.kit.ExceptionKit; import cn.citycraft.PluginHelper.kit.PluginKit;
import pw.yumc.Yum.Yum; import pw.yumc.Yum.Yum;
import pw.yumc.Yum.events.PluginNetworkEvent; import pw.yumc.Yum.events.PluginNetworkEvent;
import pw.yumc.Yum.managers.ConfigManager; import pw.yumc.Yum.managers.ConfigManager;
public class PluginNetworkListener implements Listener { public class PluginNetworkListener implements Listener {
public String prefix = "§6[§bYum §a网络管理§6] ";
public PluginNetworkListener(final Yum yum) { public PluginNetworkListener(final Yum yum) {
Bukkit.getPluginManager().registerEvents(this, yum); Bukkit.getPluginManager().registerEvents(this, yum);
} }
@EventHandler
public void onPluginNetworkConect(final PluginNetworkEvent e) { public void onPluginNetworkConect(final PluginNetworkEvent e) {
final Plugin plugin = e.getPlugin(); final Plugin plugin = e.getPlugin();
final String urlinfo = e.getUrl().toString(); final String urlinfo = e.getUrl().toString();
final boolean isPrimaryThread = e.isPrimaryThread(); final boolean isPrimaryThread = e.isPrimaryThread();
final String str = isPrimaryThread ? "§6[§bYum §a网络管理§6] §c插件 §6%s §c尝试在主线程访问 §e%s §4可能会导致服务器卡顿或无响应!" : "§6[§bYum §a网络监控§6] §c插件 §6%s §c尝试访问 §e%s §c请注意服务器网络安全!"; final String str = prefix + (isPrimaryThread ? "§c插件 §6%s §c尝试在主线程访问 §e%s §4可能会导致服务器卡顿或无响应!" : "§c插件 §6%s §c尝试访问 §e%s §c请注意服务器网络安全!");
if (plugin != null) { if (plugin != null) {
Bukkit.getConsoleSender().sendMessage(String.format(str, plugin.getName(), urlinfo)); if (ConfigManager.i().getNetworkBlackList().contains(plugin.getName())) {
PluginKit.sc(prefix + "§4已阻止黑名单插件 §b" + plugin.getName() + " §4访问网络!");
PluginKit.sc(prefix + "§4地址: " + urlinfo);
return;
}
PluginKit.sc(String.format(str, plugin.getName(), urlinfo));
if (!ConfigManager.i().isAllowPrimaryThread() && isPrimaryThread) { if (!ConfigManager.i().isAllowPrimaryThread() && isPrimaryThread) {
Bukkit.getConsoleSender().sendMessage("§6[§bYum §a网络管理§6] §4已阻止插件 §b" + plugin.getName() + " §4在主线程访问网络!"); PluginKit.sc(prefix + "§4已阻止插件 §b" + plugin.getName() + " §4在主线程访问网络!");
ExceptionKit.throwException(new IOException("[Yum 网络防护] 已开启网络防护 不允许在主线程访问网络!")); e.setCancelled(true);
} }
} }
} }

View File

@ -8,18 +8,15 @@ import cn.citycraft.PluginHelper.config.FileConfig;
import cn.citycraft.PluginHelper.kit.PKit; import cn.citycraft.PluginHelper.kit.PKit;
public class ConfigManager { public class ConfigManager {
private static List<String> blackList;
private static List<String> ignoreList;
private final static String ENABLE = "Enable"; private final static String ENABLE = "Enable";
private final static String BLACK = "Black"; private final static String BLACK = "Black";
private final static String IGNORE = "Ignore"; private final static String IGNORE = "Ignore";
private final static ConfigManager i = new ConfigManager(PKit.i()); private final static ConfigManager i = new ConfigManager(PKit.i());
private final FileConfig config; public final FileConfig config;
private final FileConfig setop; public final FileConfig setop;
private final FileConfig network; public final FileConfig network;
public static ConfigManager i() { public static ConfigManager i() {
return i; return i;
@ -32,11 +29,11 @@ public class ConfigManager {
} }
public List<String> getBlackList() { public List<String> getBlackList() {
return blackList; return config.getStringList("blacklist");
} }
public List<String> getIgnoreList() { public List<String> getIgnoreList() {
return ignoreList; return config.getStringList("ignorelist");
} }
public List<String> getNetworkBlackList() { public List<String> getNetworkBlackList() {

View File

@ -8,8 +8,8 @@ import java.net.URI;
import java.util.List; import java.util.List;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import cn.citycraft.PluginHelper.kit.ExceptionKit;
import cn.citycraft.PluginHelper.kit.PluginKit; import cn.citycraft.PluginHelper.kit.PluginKit;
import pw.yumc.Yum.Yum; import pw.yumc.Yum.Yum;
import pw.yumc.Yum.events.PluginNetworkEvent; import pw.yumc.Yum.events.PluginNetworkEvent;
@ -22,20 +22,19 @@ import pw.yumc.Yum.events.PluginNetworkEvent;
*/ */
public class NetworkManager { public class NetworkManager {
public NetworkManager register(final Yum plugin) { public static void register(final Yum plugin) {
Bukkit.getConsoleSender().sendMessage("§6[§bYum §a网络管理§6] §a注入网络管理系统 将托管服务器网络!"); Bukkit.getConsoleSender().sendMessage("§6[§bYum §a网络管理§6] §a注入网络管理系统 将托管服务器网络!");
ProxySelector.setDefault(new YumProxySelector(ProxySelector.getDefault(), plugin)); ProxySelector.setDefault(new YumProxySelector(ProxySelector.getDefault(), plugin));
return this;
} }
public void unregister() { public static void unregister() {
final ProxySelector cur = ProxySelector.getDefault(); final ProxySelector cur = ProxySelector.getDefault();
if (cur instanceof YumProxySelector) { if (cur instanceof YumProxySelector) {
ProxySelector.setDefault(((YumProxySelector) cur).getDefaultSelector()); ProxySelector.setDefault(((YumProxySelector) cur).getDefaultSelector());
} }
} }
class YumProxySelector extends ProxySelector { static class YumProxySelector extends ProxySelector {
private final ProxySelector defaultSelector; private final ProxySelector defaultSelector;
public YumProxySelector(final ProxySelector defaultSelector, final Yum plugin) { public YumProxySelector(final ProxySelector defaultSelector, final Yum plugin) {
@ -53,12 +52,10 @@ public class NetworkManager {
@Override @Override
public List<Proxy> select(final URI uri) { public List<Proxy> select(final URI uri) {
final boolean isPrimaryThread = Bukkit.isPrimaryThread(); final PluginNetworkEvent pne = new PluginNetworkEvent(PluginKit.getOperatePlugin(), uri, Bukkit.isPrimaryThread());
final Plugin plugin = PluginKit.getOperatePlugin();
final PluginNetworkEvent pne = new PluginNetworkEvent(plugin, uri, isPrimaryThread);
Bukkit.getPluginManager().callEvent(pne); Bukkit.getPluginManager().callEvent(pne);
if (pne.isCancelled()) { if (pne.isCancelled()) {
return null; ExceptionKit.throwException(new IOException("[Yum 网络防护] 已开启网络防护 不允许在主线程访问网络!"));
} }
return defaultSelector.select(uri); return defaultSelector.select(uri);
} }

View File

@ -0,0 +1,53 @@
package pw.yumc.Yum.runnables;
import java.lang.Thread.State;
import java.util.TimerTask;
import java.util.logging.Level;
import cn.citycraft.PluginHelper.kit.PKit;
/**
*
* @since 2016年6月22日 下午4:57:32
* @author
*/
public class MainThreadCheckTask extends TimerTask {
private final Thread mainThread;
public MainThreadCheckTask(final Thread mainThread) {
this.mainThread = mainThread;
}
@Override
public void run() {
// According to this post the thread is still in Runnable although it's waiting for
// file/http ressources
// https://stackoverflow.com/questions/20795295/why-jstack-out-says-thread-state-is-runnable-while-socketread
if (mainThread.getState() == State.RUNNABLE) {
// Based on this post we have to check the top element of the stack
// https://stackoverflow.com/questions/20891386/how-to-detect-thread-being-blocked-by-io
final StackTraceElement[] stackTrace = mainThread.getStackTrace();
final StackTraceElement topElement = stackTrace[0];
if (topElement.isNativeMethod()) {
// Socket/SQL (connect) - java.net.DualStackPlainSocketImpl.connect0
// Socket/SQL (read) - java.net.SocketInputStream.socketRead0
// Socket/SQL (write) - java.net.SocketOutputStream.socketWrite0
if (isElementEqual(topElement, "java.net.DualStackPlainSocketImpl", "connect0")
|| isElementEqual(topElement, "java.net.SocketInputStream", "socketRead0")
|| isElementEqual(topElement, "java.net.SocketOutputStream", "socketWrite0")) {
PKit.i().getLogger().log(Level.WARNING, "主线程存在网络操作 服务器处于停止状态...", stackTrace);
}
// File (in) - java.io.FileInputStream.readBytes
// File (out) - java.io.FileOutputStream.writeBytes
else if (isElementEqual(topElement, "java.io.FileInputStream", "readBytes") || isElementEqual(topElement, "java.io.FileOutputStream", "writeBytes")) {
PKit.i().getLogger().log(Level.WARNING, "主线程存在IO操作 服务器处于停止状态...", stackTrace);
}
}
}
}
private boolean isElementEqual(final StackTraceElement traceElement, final String className, final String methodName) {
return traceElement.getClassName().equals(className) && traceElement.getMethodName().equals(methodName);
}
}

View File

@ -3,6 +3,7 @@ Enable: true
#黑名单列表 #黑名单列表
Black: Black:
- BukkitInjectedTools - BukkitInjectedTools
- FeatherBoard
#忽略检测列表 #忽略检测列表
Ignore: Ignore:
- Essentials - Essentials