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>
<groupId>pw.yumc</groupId>
<artifactId>Yum</artifactId>
<version>2.1</version>
<version>2.2</version>
<name>Yum</name>
<description>Minecraft 服务器插件管理系统</description>
<build>

View File

@ -3,7 +3,10 @@
*/
package pw.yumc.Yum;
import java.util.Timer;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
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.managers.ConfigManager;
import pw.yumc.Yum.managers.NetworkManager;
import pw.yumc.Yum.runnables.MainThreadCheckTask;
/**
* MC插件仓库
@ -25,15 +29,50 @@ import pw.yumc.Yum.managers.NetworkManager;
* @since 2015年8月21日下午5:14:39
*/
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 NetCommand(this);
new FileCommand(this);
}
public void initListeners() {
/**
* 初始化监听
*/
private void initListeners() {
if (ConfigManager.i().isSetOpEnable()) {
try {
final ClassLoader cl = Class.forName("pw.yumc.injected.event.SetOpEvent").getClassLoader();
@ -52,30 +91,15 @@ public class Yum extends JavaPlugin {
new PluginNetworkListener(this);
PluginKit.scp("§a网络管理系统已启用...");
}
new
}
@Override
public void onDisable() {
netmgr.unregister();
}
@Override
public void onEnable() {
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);
/**
* 初始化任务
*/
private void initRunnable() {
final Timer task = new Timer();
PluginKit.scp("§a线程管理系统已启用...");
task.scheduleAtFixedRate(new MainThreadCheckTask(Thread.currentThread()), 0, 3000);
}
}

View File

@ -11,6 +11,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import cn.citycraft.CommonData.UpdatePlugin;
import pw.yumc.Yum.managers.ConfigManager;
import pw.yumc.Yum.managers.DownloadManager;
import pw.yumc.Yum.managers.PluginsManager;
import pw.yumc.Yum.managers.RepositoryManager;
@ -29,20 +30,6 @@ public class YumAPI {
private static RepositoryManager repo;
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) {
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;
import java.io.IOException;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
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.events.PluginNetworkEvent;
import pw.yumc.Yum.managers.ConfigManager;
public class PluginNetworkListener implements Listener {
public String prefix = "§6[§bYum §a网络管理§6] ";
public PluginNetworkListener(final Yum yum) {
Bukkit.getPluginManager().registerEvents(this, yum);
}
@EventHandler
public void onPluginNetworkConect(final PluginNetworkEvent e) {
final Plugin plugin = e.getPlugin();
final String urlinfo = e.getUrl().toString();
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) {
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) {
Bukkit.getConsoleSender().sendMessage("§6[§bYum §a网络管理§6] §4已阻止插件 §b" + plugin.getName() + " §4在主线程访问网络!");
ExceptionKit.throwException(new IOException("[Yum 网络防护] 已开启网络防护 不允许在主线程访问网络!"));
PluginKit.sc(prefix + "§4已阻止插件 §b" + plugin.getName() + " §4在主线程访问网络!");
e.setCancelled(true);
}
}
}

View File

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

View File

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