Merged with released L2J-Unity files.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.network.telnet;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public interface ITelnetCommand
|
||||
{
|
||||
String getCommand();
|
||||
|
||||
String getUsage();
|
||||
|
||||
String handle(ChannelHandlerContext ctx, String[] args);
|
||||
}
|
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.network.telnet;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.l2jmobius.Config;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class TelnetServer
|
||||
{
|
||||
private static final Logger LOGGER = Logger.getLogger(TelnetServer.class.getName());
|
||||
private final Map<String, ITelnetCommand> _commands = new LinkedHashMap<>();
|
||||
private final EventLoopGroup _workerGroup = new NioEventLoopGroup(1);
|
||||
|
||||
protected TelnetServer()
|
||||
{
|
||||
if (Config.TELNET_ENABLED)
|
||||
{
|
||||
init();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.info("Telnet server is currently disabled.");
|
||||
}
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
addHandler(new ITelnetCommand()
|
||||
{
|
||||
@Override
|
||||
public String getCommand()
|
||||
{
|
||||
return "help";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage()
|
||||
{
|
||||
return "help [command]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(ChannelHandlerContext ctx, String[] args)
|
||||
{
|
||||
if (args.length == 0)
|
||||
{
|
||||
final StringBuilder sb = new StringBuilder("Available commands:" + Config.EOL);
|
||||
for (ITelnetCommand cmd : TelnetServer.getInstance().getCommands())
|
||||
{
|
||||
sb.append(cmd.getCommand() + Config.EOL);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
final ITelnetCommand cmd = TelnetServer.getInstance().getCommand(args[0]);
|
||||
if (cmd == null)
|
||||
{
|
||||
return "Unknown command." + Config.EOL;
|
||||
}
|
||||
return "Usage:" + Config.EOL + cmd.getUsage() + Config.EOL;
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
final InetSocketAddress socket = Config.TELNET_HOSTNAME.equals("*") ? new InetSocketAddress(Config.TELNET_PORT) : new InetSocketAddress(Config.TELNET_HOSTNAME, Config.TELNET_PORT);
|
||||
//@formatter:off
|
||||
new ServerBootstrap().group(_workerGroup)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.option(ChannelOption.SO_KEEPALIVE, true)
|
||||
.childHandler(new TelnetServerInitializer())
|
||||
.bind(socket);
|
||||
//@formatter:on
|
||||
LOGGER.info(getClass().getSimpleName() + ": Listening on " + Config.TELNET_HOSTNAME + ":" + Config.TELNET_PORT);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void addHandler(ITelnetCommand handler)
|
||||
{
|
||||
_commands.put(handler.getCommand(), handler);
|
||||
}
|
||||
|
||||
public ITelnetCommand getCommand(String command)
|
||||
{
|
||||
return _commands.get(command);
|
||||
}
|
||||
|
||||
public Collection<ITelnetCommand> getCommands()
|
||||
{
|
||||
return _commands.values();
|
||||
}
|
||||
|
||||
public void shutdown()
|
||||
{
|
||||
_workerGroup.shutdownGracefully();
|
||||
LOGGER.info("Shutting down..");
|
||||
}
|
||||
|
||||
public static TelnetServer getInstance()
|
||||
{
|
||||
return SingletonHolder._instance;
|
||||
}
|
||||
|
||||
private static class SingletonHolder
|
||||
{
|
||||
protected static final TelnetServer _instance = new TelnetServer();
|
||||
}
|
||||
}
|
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.network.telnet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.l2jmobius.Config;
|
||||
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
import io.netty.channel.ChannelHandlerAdapter;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.util.AttributeKey;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
@Sharable
|
||||
public class TelnetServerHandler extends ChannelHandlerAdapter
|
||||
{
|
||||
private static final Pattern COMMAND_ARGS_PATTERN = Pattern.compile("\"([^\"]*)\"|([^\\s]+)");
|
||||
private static final AttributeKey<Boolean> AUTHORIZED = AttributeKey.valueOf(TelnetServerHandler.class, "AUTHORIZED");
|
||||
|
||||
private String tryHandleCommand(ChannelHandlerContext ctx, String command, String[] args)
|
||||
{
|
||||
final ITelnetCommand cmd = TelnetServer.getInstance().getCommand(command);
|
||||
if (cmd == null)
|
||||
{
|
||||
return "Unknown command." + Config.EOL;
|
||||
}
|
||||
|
||||
String response = cmd.handle(ctx, args);
|
||||
if (response == null)
|
||||
{
|
||||
response = "Usage:" + Config.EOL + cmd.getUsage() + Config.EOL;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx)
|
||||
{
|
||||
String ip = ctx.channel().remoteAddress().toString();
|
||||
ip = ip.substring(1, ip.lastIndexOf(':')); // Trim out /127.0.0.1:14013
|
||||
|
||||
if (!Config.TELNET_HOSTS.contains(ip))
|
||||
{
|
||||
final ChannelFuture future = ctx.write("Your ip: " + ip + " is not allowed to connect." + Config.EOL);
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
ctx.flush();
|
||||
return;
|
||||
}
|
||||
|
||||
// Send greeting for a new connection.
|
||||
ctx.write("Welcome to the telnet session." + Config.EOL);
|
||||
ctx.write("It is " + new Date() + " now." + Config.EOL);
|
||||
ctx.write("Please enter your password:" + Config.EOL);
|
||||
if (!Config.TELNET_PASSWORD.isEmpty())
|
||||
{
|
||||
// Ask password
|
||||
ctx.write("Password:");
|
||||
ctx.attr(AUTHORIZED).set(Boolean.FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.write("Type 'help' to see all available commands." + Config.EOL);
|
||||
ctx.attr(AUTHORIZED).set(Boolean.TRUE);
|
||||
}
|
||||
ctx.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg)
|
||||
{
|
||||
// Cast to a String first.
|
||||
// We know it is a String because we put some codec in TelnetPipelineFactory.
|
||||
String request = (String) msg;
|
||||
|
||||
// Generate and write a response.
|
||||
String response = null;
|
||||
boolean close = false;
|
||||
|
||||
if (Boolean.FALSE.equals(ctx.attr(AUTHORIZED).get()))
|
||||
{
|
||||
if (Config.TELNET_PASSWORD.equals(request))
|
||||
{
|
||||
ctx.attr(AUTHORIZED).set(Boolean.TRUE);
|
||||
request = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
response = "Wrong password!" + Config.EOL;
|
||||
close = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Boolean.TRUE.equals(ctx.attr(AUTHORIZED).get()))
|
||||
{
|
||||
if (request.isEmpty())
|
||||
{
|
||||
response = "Type 'help' to see all available commands." + Config.EOL;
|
||||
}
|
||||
else if (request.toLowerCase().equals("exit"))
|
||||
{
|
||||
response = "Have a good day!" + Config.EOL;
|
||||
close = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
final Matcher m = COMMAND_ARGS_PATTERN.matcher(request);
|
||||
|
||||
if (m.find())
|
||||
{
|
||||
final String command = m.group();
|
||||
final List<String> args = new ArrayList<>();
|
||||
String arg;
|
||||
|
||||
while (m.find())
|
||||
{
|
||||
arg = m.group(1);
|
||||
|
||||
if (arg == null)
|
||||
{
|
||||
arg = m.group(0);
|
||||
}
|
||||
|
||||
args.add(arg);
|
||||
}
|
||||
|
||||
response = tryHandleCommand(ctx, command, args.toArray(new String[args.size()]));
|
||||
if (!response.endsWith(Config.EOL))
|
||||
{
|
||||
response += Config.EOL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We do not need to write a ChannelBuffer here.
|
||||
// We know the encoder inserted at TelnetPipelineFactory will do the conversion.
|
||||
final ChannelFuture future = ctx.write(response);
|
||||
|
||||
// Close the connection after sending 'Have a good day!'
|
||||
// if the client has sent 'exit'.
|
||||
if (close)
|
||||
{
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelReadComplete(ChannelHandlerContext ctx)
|
||||
{
|
||||
ctx.flush();
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of the L2J Mobius project.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jmobius.gameserver.network.telnet;
|
||||
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
|
||||
import io.netty.handler.codec.Delimiters;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.codec.string.StringEncoder;
|
||||
|
||||
/**
|
||||
* @author UnAfraid
|
||||
*/
|
||||
public class TelnetServerInitializer extends ChannelInitializer<SocketChannel>
|
||||
{
|
||||
private static final StringEncoder ENCODER = new StringEncoder();
|
||||
private static final StringDecoder DECODER = new StringDecoder();
|
||||
private static final TelnetServerHandler HANDLER = new TelnetServerHandler();
|
||||
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch)
|
||||
{
|
||||
final ChannelPipeline pipeline = ch.pipeline();
|
||||
|
||||
// Add the text line codec combination first,
|
||||
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
|
||||
pipeline.addLast(DECODER);
|
||||
pipeline.addLast(ENCODER);
|
||||
pipeline.addLast(HANDLER);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user