* Got the basics working
This commit is contained in:
parent
6c07fd17d4
commit
98ae84bf58
|
|
@ -88,4 +88,10 @@ public class SharedProxy {
|
||||||
return FMLServerHandler.instance().getServer();
|
return FMLServerHandler.instance().getServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMiniservClientPort(int port) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startMiniServClient() {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,7 @@ import net.minecraftforge.event.entity.item.ItemTossEvent;
|
||||||
import net.minecraftforge.event.world.WorldEvent;
|
import net.minecraftforge.event.world.WorldEvent;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.common.SidedProxy;
|
import net.minecraftforge.fml.common.SidedProxy;
|
||||||
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
import net.minecraftforge.fml.common.event.*;
|
||||||
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
|
|
||||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
|
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
|
||||||
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||||
|
|
@ -36,6 +34,9 @@ import net.montoyo.wd.block.BlockScreen;
|
||||||
import net.montoyo.wd.core.*;
|
import net.montoyo.wd.core.*;
|
||||||
import net.montoyo.wd.entity.TileEntityScreen;
|
import net.montoyo.wd.entity.TileEntityScreen;
|
||||||
import net.montoyo.wd.item.*;
|
import net.montoyo.wd.item.*;
|
||||||
|
import net.montoyo.wd.miniserv.client.Client;
|
||||||
|
import net.montoyo.wd.miniserv.server.Server;
|
||||||
|
import net.montoyo.wd.net.CMessageServerInfo;
|
||||||
import net.montoyo.wd.net.Messages;
|
import net.montoyo.wd.net.Messages;
|
||||||
import net.montoyo.wd.utilities.Log;
|
import net.montoyo.wd.utilities.Log;
|
||||||
import net.montoyo.wd.utilities.Util;
|
import net.montoyo.wd.utilities.Util;
|
||||||
|
|
@ -183,7 +184,8 @@ public class WebDisplays {
|
||||||
if(ev.getWorld().isRemote || ev.getWorld().provider.getDimension() != 0)
|
if(ev.getWorld().isRemote || ev.getWorld().provider.getDimension() != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
File f = new File(ev.getWorld().getSaveHandler().getWorldDirectory(), "wd_next.txt");
|
File worldDir = ev.getWorld().getSaveHandler().getWorldDirectory();
|
||||||
|
File f = new File(worldDir, "wd_next.txt");
|
||||||
|
|
||||||
if(f.exists()) {
|
if(f.exists()) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -203,6 +205,10 @@ public class WebDisplays {
|
||||||
Log.warningEx("Could not read last minePad ID from %s. I'm afraid this might break all minePads.", t, f.getAbsolutePath());
|
Log.warningEx("Could not read last minePad ID from %s. I'm afraid this might break all minePads.", t, f.getAbsolutePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Server sv = Server.getInstance();
|
||||||
|
sv.setDirectory(new File(worldDir, "wd_filehost"));
|
||||||
|
sv.start(); //TODO: Configure port
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
|
|
@ -254,6 +260,23 @@ public class WebDisplays {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Mod.EventHandler
|
||||||
|
public void onServerStop(FMLServerStoppingEvent ev) {
|
||||||
|
Server.getInstance().stopServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onLogIn(PlayerEvent.PlayerLoggedInEvent ev) {
|
||||||
|
if(!ev.player.world.isRemote && ev.player instanceof EntityPlayerMP)
|
||||||
|
WebDisplays.NET_HANDLER.sendTo(new CMessageServerInfo(25566), (EntityPlayerMP) ev.player); //TODO: Port config
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void onLogOut(PlayerEvent.PlayerLoggedOutEvent ev) {
|
||||||
|
if(!ev.player.world.isRemote)
|
||||||
|
Server.getInstance().getClientManager().revokeClientKey(ev.player.getGameProfile().getId());
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasPlayerAdvancement(EntityPlayerMP ply, ResourceLocation rl) {
|
private boolean hasPlayerAdvancement(EntityPlayerMP ply, ResourceLocation rl) {
|
||||||
MinecraftServer server = PROXY.getServer();
|
MinecraftServer server = PROXY.getServer();
|
||||||
if(server == null)
|
if(server == null)
|
||||||
|
|
|
||||||
|
|
@ -52,12 +52,15 @@ import net.montoyo.wd.core.JSServerRequest;
|
||||||
import net.montoyo.wd.data.GuiData;
|
import net.montoyo.wd.data.GuiData;
|
||||||
import net.montoyo.wd.entity.TileEntityScreen;
|
import net.montoyo.wd.entity.TileEntityScreen;
|
||||||
import net.montoyo.wd.item.ItemMulti;
|
import net.montoyo.wd.item.ItemMulti;
|
||||||
|
import net.montoyo.wd.miniserv.client.Client;
|
||||||
import net.montoyo.wd.net.SMessagePadCtrl;
|
import net.montoyo.wd.net.SMessagePadCtrl;
|
||||||
import net.montoyo.wd.net.SMessageScreenCtrl;
|
import net.montoyo.wd.net.SMessageScreenCtrl;
|
||||||
import net.montoyo.wd.utilities.*;
|
import net.montoyo.wd.utilities.*;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.SocketAddress;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class ClientProxy extends SharedProxy implements IResourceManagerReloadListener, IDisplayHandler, IJSQueryHandler {
|
public class ClientProxy extends SharedProxy implements IResourceManagerReloadListener, IDisplayHandler, IJSQueryHandler {
|
||||||
|
|
@ -84,6 +87,8 @@ public class ClientProxy extends SharedProxy implements IResourceManagerReloadLi
|
||||||
private MinePadRenderer minePadRenderer;
|
private MinePadRenderer minePadRenderer;
|
||||||
private JSQueryDispatcher jsDispatcher;
|
private JSQueryDispatcher jsDispatcher;
|
||||||
private LaserPointerRenderer laserPointerRenderer;
|
private LaserPointerRenderer laserPointerRenderer;
|
||||||
|
private int miniservPort;
|
||||||
|
private boolean msClientStarted;
|
||||||
|
|
||||||
//Client-side advancement hack
|
//Client-side advancement hack
|
||||||
private final Field advancementToProgressField = findAdvancementToProgressField();
|
private final Field advancementToProgressField = findAdvancementToProgressField();
|
||||||
|
|
@ -295,6 +300,34 @@ public class ClientProxy extends SharedProxy implements IResourceManagerReloadLi
|
||||||
q.error(errCode, err);
|
q.error(errCode, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMiniservClientPort(int port) {
|
||||||
|
miniservPort = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startMiniServClient() {
|
||||||
|
if(miniservPort <= 0) {
|
||||||
|
Log.warning("Can't start miniserv client: miniserv is disabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mc.player == null) {
|
||||||
|
Log.warning("Can't start miniserv client: player is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketAddress saddr = mc.player.connection.getNetworkManager().channel().remoteAddress();
|
||||||
|
if(saddr == null || !(saddr instanceof InetSocketAddress)) {
|
||||||
|
Log.warning("Miniserv client: remote address is not inet, assuming local address");
|
||||||
|
saddr = new InetSocketAddress("127.0.0.1", 1234);
|
||||||
|
}
|
||||||
|
|
||||||
|
InetSocketAddress msAddr = new InetSocketAddress(((InetSocketAddress) saddr).getAddress(), miniservPort);
|
||||||
|
Client.getInstance().start(msAddr);
|
||||||
|
msClientStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************** RESOURCE MANAGER METHODS ****************************************/
|
/**************************************** RESOURCE MANAGER METHODS ****************************************/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -507,6 +540,12 @@ public class ClientProxy extends SharedProxy implements IResourceManagerReloadLi
|
||||||
|
|
||||||
//Handle JS queries
|
//Handle JS queries
|
||||||
jsDispatcher.handleQueries();
|
jsDispatcher.handleQueries();
|
||||||
|
|
||||||
|
//Stop miniserv client
|
||||||
|
if(mc.player == null && msClientStarted) {
|
||||||
|
msClientStarted = false;
|
||||||
|
Client.getInstance().stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
112
src/main/java/net/montoyo/wd/client/WDScheme.java
Normal file
112
src/main/java/net/montoyo/wd/client/WDScheme.java
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.client;
|
||||||
|
|
||||||
|
import net.montoyo.mcef.api.IScheme;
|
||||||
|
import net.montoyo.mcef.api.ISchemeResponseData;
|
||||||
|
import net.montoyo.mcef.api.ISchemeResponseHeaders;
|
||||||
|
import net.montoyo.mcef.api.SchemePreResponse;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.miniserv.Constants;
|
||||||
|
import net.montoyo.wd.miniserv.client.Client;
|
||||||
|
import net.montoyo.wd.miniserv.client.ClientTaskGetFile;
|
||||||
|
import net.montoyo.wd.utilities.Util;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class WDScheme implements IScheme {
|
||||||
|
|
||||||
|
private ClientTaskGetFile task;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SchemePreResponse processRequest(String url) {
|
||||||
|
url = url.substring("wd://".length());
|
||||||
|
|
||||||
|
int pos = url.indexOf('/');
|
||||||
|
if(pos < 0)
|
||||||
|
return SchemePreResponse.NOT_HANDLED;
|
||||||
|
|
||||||
|
String uuidStr = url.substring(0, pos);
|
||||||
|
String fileStr = url.substring(pos + 1);
|
||||||
|
|
||||||
|
if(uuidStr.isEmpty() || Util.isFileNameInvalid(fileStr))
|
||||||
|
return SchemePreResponse.NOT_HANDLED;
|
||||||
|
|
||||||
|
UUID uuid;
|
||||||
|
try {
|
||||||
|
uuid = UUID.fromString(uuidStr);
|
||||||
|
} catch(IllegalArgumentException ex) {
|
||||||
|
return SchemePreResponse.NOT_HANDLED; //Invalid UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
task = new ClientTaskGetFile(uuid, fileStr);
|
||||||
|
return Client.getInstance().addTask(task) ? SchemePreResponse.HANDLED_CONTINUE : SchemePreResponse.NOT_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getResponseHeaders(ISchemeResponseHeaders resp) {
|
||||||
|
int status = task.waitForResponse();
|
||||||
|
|
||||||
|
if(status == 0) {
|
||||||
|
//OK
|
||||||
|
int extPos = task.getFileName().lastIndexOf('.');
|
||||||
|
if(extPos >= 0) {
|
||||||
|
String mime = ((ClientProxy) WebDisplays.PROXY).getMCEF().mimeTypeFromExtension(task.getFileName().substring(extPos + 1));
|
||||||
|
|
||||||
|
if(mime != null)
|
||||||
|
resp.setMimeType(mime);
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.setStatus(200);
|
||||||
|
resp.setStatusText("OK");
|
||||||
|
resp.setResponseLength(-1);
|
||||||
|
} else if(status == Constants.GETF_STATUS_NOT_FOUND) {
|
||||||
|
resp.setStatus(404);
|
||||||
|
resp.setStatusText("Not Found");
|
||||||
|
resp.setResponseLength(0);
|
||||||
|
} else {
|
||||||
|
resp.setStatus(500);
|
||||||
|
resp.setStatusText("Internal Server Error");
|
||||||
|
resp.setResponseLength(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] dataToWrite;
|
||||||
|
private int dataOffset;
|
||||||
|
private int amountToWrite;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean readResponse(ISchemeResponseData data) {
|
||||||
|
if(dataToWrite == null) {
|
||||||
|
dataToWrite = task.waitForData();
|
||||||
|
dataOffset = 3; //packet ID + size
|
||||||
|
amountToWrite = task.getDataLength();
|
||||||
|
|
||||||
|
if(amountToWrite <= 0) {
|
||||||
|
dataToWrite = null;
|
||||||
|
data.setAmountRead(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int toWrite = data.getBytesToRead();
|
||||||
|
if(toWrite > amountToWrite)
|
||||||
|
toWrite = amountToWrite;
|
||||||
|
|
||||||
|
System.arraycopy(dataToWrite, dataOffset, data.getDataArray(), 0, toWrite);
|
||||||
|
data.setAmountRead(toWrite);
|
||||||
|
|
||||||
|
dataOffset += toWrite;
|
||||||
|
amountToWrite -= toWrite;
|
||||||
|
|
||||||
|
if(amountToWrite <= 0) {
|
||||||
|
task.nextData();
|
||||||
|
dataToWrite = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -28,7 +28,7 @@ public abstract class AbstractClient {
|
||||||
private final Method[] packetHandlers = new Method[PacketID.values().length];
|
private final Method[] packetHandlers = new Method[PacketID.values().length];
|
||||||
protected SocketChannel socket;
|
protected SocketChannel socket;
|
||||||
protected Selector selector;
|
protected Selector selector;
|
||||||
private SelectionKey writeKey;
|
protected SelectionKey selKey;
|
||||||
|
|
||||||
public AbstractClient() {
|
public AbstractClient() {
|
||||||
sendBuffer.limit(0);
|
sendBuffer.limit(0);
|
||||||
|
|
@ -67,13 +67,17 @@ public abstract class AbstractClient {
|
||||||
|
|
||||||
if(pid >= packetHandlers.length)
|
if(pid >= packetHandlers.length)
|
||||||
Log.error("Caught invalid packet ID %d", pid);
|
Log.error("Caught invalid packet ID %d", pid);
|
||||||
else if(packetHandlers[pid] != null) {
|
else {
|
||||||
try {
|
Log.info("Received PID %s", PacketID.fromInt(pid).toString());
|
||||||
packetHandlers[pid].invoke(this, dis); //This is slow, I know... sorry
|
|
||||||
} catch(IllegalAccessException ex) {
|
if(packetHandlers[pid] != null) {
|
||||||
Log.errorEx("This shouldn't have happened", ex);
|
try {
|
||||||
} catch(InvocationTargetException ex) {
|
packetHandlers[pid].invoke(this, dis); //This is slow, I know... sorry
|
||||||
Log.warningEx("Caught exception while handling packet %d", ex.getTargetException(), pid);
|
} catch(IllegalAccessException ex) {
|
||||||
|
Log.errorEx("This shouldn't have happened", ex);
|
||||||
|
} catch(InvocationTargetException ex) {
|
||||||
|
Log.warningEx("Caught exception while handling packet %d", ex.getTargetException(), pid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch(IOException ex) {
|
} catch(IOException ex) {
|
||||||
|
|
@ -88,8 +92,13 @@ public abstract class AbstractClient {
|
||||||
|
|
||||||
public void readyWrite() throws Throwable {
|
public void readyWrite() throws Throwable {
|
||||||
if(sendBuffer.remaining() > 0 || fillSendBuffer()) {
|
if(sendBuffer.remaining() > 0 || fillSendBuffer()) {
|
||||||
if(socket.write(sendBuffer) < 0)
|
int sent = socket.write(sendBuffer);
|
||||||
|
Log.info("Sent %d bytes", sent);
|
||||||
|
|
||||||
|
if(sent < 0) {
|
||||||
|
Log.error("Error when sending data");
|
||||||
onWriteError();
|
onWriteError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,12 +112,8 @@ public abstract class AbstractClient {
|
||||||
pkt = sendQueue.poll();
|
pkt = sendQueue.poll();
|
||||||
|
|
||||||
if(pkt == null) {
|
if(pkt == null) {
|
||||||
if(writeKey != null) {
|
selKey.interestOps(SelectionKey.OP_READ); //Remove write op
|
||||||
writeKey.cancel();
|
break;
|
||||||
writeKey = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sendBuffer.remaining() > 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,19 +121,19 @@ public abstract class AbstractClient {
|
||||||
}
|
}
|
||||||
} while(sendBuffer.remaining() > 0);
|
} while(sendBuffer.remaining() > 0);
|
||||||
|
|
||||||
return true;
|
int pos = sendBuffer.position();
|
||||||
|
sendBuffer.position(0);
|
||||||
|
sendBuffer.limit(pos);
|
||||||
|
return pos > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendPacket(OutgoingPacket pkt) {
|
public void sendPacket(OutgoingPacket pkt) {
|
||||||
synchronized(sendQueue) {
|
synchronized(sendQueue) {
|
||||||
sendQueue.offer(pkt);
|
sendQueue.offer(pkt);
|
||||||
|
|
||||||
if(writeKey == null) {
|
if((selKey.interestOps() & SelectionKey.OP_WRITE) == 0) {
|
||||||
try {
|
selKey.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
|
||||||
writeKey = socket.register(selector, SelectionKey.OP_WRITE);
|
selector.wakeup(); //Is this needed?
|
||||||
} catch(ClosedChannelException ex) {
|
|
||||||
Log.warningEx("Couldn't send packet", ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -149,4 +154,11 @@ public abstract class AbstractClient {
|
||||||
return packetReader.getPacketData();
|
return packetReader.getPacketData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void clearSendQueue() {
|
||||||
|
synchronized(sendQueue) {
|
||||||
|
packetWriter.clear();
|
||||||
|
sendQueue.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
src/main/java/net/montoyo/wd/miniserv/Constants.java
Normal file
24
src/main/java/net/montoyo/wd/miniserv/Constants.java
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.miniserv;
|
||||||
|
|
||||||
|
public abstract class Constants {
|
||||||
|
|
||||||
|
public static int FUPA_STATUS_BAD_NAME = 1;
|
||||||
|
public static int FUPA_STATUS_INVALID_SIZE = 2;
|
||||||
|
public static int FUPA_STATUS_EXCEEDS_QUOTA = 3;
|
||||||
|
public static int FUPA_STATUS_OCCUPIED = 4;
|
||||||
|
public static int FUPA_STATUS_FILE_EXISTS = 5;
|
||||||
|
public static int FUPA_STATUS_INTERNAL_ERROR = 6;
|
||||||
|
public static int FUPA_STATUS_USER_ABORT = 7;
|
||||||
|
public static int FUPA_STATUS_LIER = 8;
|
||||||
|
public static int FUPA_STATUS_CONNECTION_LOST = 9;
|
||||||
|
|
||||||
|
public static int GETF_STATUS_BAD_NAME = 1;
|
||||||
|
public static int GETF_STATUS_NOT_FOUND = 2;
|
||||||
|
public static int GETF_STATUS_INTERNAL_ERROR = 3;
|
||||||
|
public static int GETF_STATUS_CONNECTION_LOST = 4;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,12 @@ public final class OutgoingPacket {
|
||||||
dos = new DataOutputStream(baos);
|
dos = new DataOutputStream(baos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void writeLong(long l) {
|
||||||
|
try {
|
||||||
|
dos.writeLong(l);
|
||||||
|
} catch(IOException ex) {}
|
||||||
|
}
|
||||||
|
|
||||||
public final void writeInt(int i) {
|
public final void writeInt(int i) {
|
||||||
try {
|
try {
|
||||||
dos.writeInt(i);
|
dos.writeInt(i);
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,16 @@ public final class PacketReader {
|
||||||
return true; //Abort packet reading
|
return true; //Abort packet reading
|
||||||
}
|
}
|
||||||
|
|
||||||
|
packetSize -= 4;
|
||||||
packetData = new byte[packetSize];
|
packetData = new byte[packetSize];
|
||||||
|
Log.info("Awaiting packet of size %d", packetSize);
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return readByteArray(packetData, buf);
|
boolean ret = readByteArray(packetData, buf);
|
||||||
|
Log.info("Read %d out of %d, ok = %s", pos, packetData.length, ret ? "true" : "false");
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean readByteArray(byte[] dst, ByteBuffer src) {
|
private boolean readByteArray(byte[] dst, ByteBuffer src) {
|
||||||
|
|
|
||||||
|
|
@ -53,4 +53,10 @@ public final class PacketWriter {
|
||||||
needToWriteSize = true;
|
needToWriteSize = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void clear() {
|
||||||
|
packet = null;
|
||||||
|
pos = 0;
|
||||||
|
needToWriteSize = true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
package net.montoyo.wd.miniserv.client;
|
package net.montoyo.wd.miniserv.client;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.montoyo.wd.miniserv.*;
|
import net.montoyo.wd.miniserv.*;
|
||||||
import net.montoyo.wd.net.SMessageMiniservConnect;
|
import net.montoyo.wd.net.SMessageMiniservConnect;
|
||||||
import net.montoyo.wd.utilities.Log;
|
import net.montoyo.wd.utilities.Log;
|
||||||
|
|
@ -20,6 +21,8 @@ import java.nio.channels.Selector;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.interfaces.RSAPublicKey;
|
import java.security.interfaces.RSAPublicKey;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class Client extends AbstractClient implements Runnable {
|
public class Client extends AbstractClient implements Runnable {
|
||||||
|
|
||||||
|
|
@ -36,10 +39,14 @@ public class Client extends AbstractClient implements Runnable {
|
||||||
private KeyPair keyPair;
|
private KeyPair keyPair;
|
||||||
private byte[] key;
|
private byte[] key;
|
||||||
private SocketAddress address;
|
private SocketAddress address;
|
||||||
private boolean running = true;
|
private volatile boolean running;
|
||||||
|
private volatile boolean connected;
|
||||||
private final ByteBuffer readBuffer = ByteBuffer.allocateDirect(8192);
|
private final ByteBuffer readBuffer = ByteBuffer.allocateDirect(8192);
|
||||||
private final Thread thread = new Thread(this);
|
private volatile Thread thread;
|
||||||
private boolean authenticated = false;
|
private final UUID clientUUID = Minecraft.getMinecraft().player.getGameProfile().getId();
|
||||||
|
private final ArrayDeque<ClientTask> tasks = new ArrayDeque<>();
|
||||||
|
private ClientTask currentTask;
|
||||||
|
private volatile boolean authenticated;
|
||||||
|
|
||||||
public SMessageMiniservConnect beginConnection() {
|
public SMessageMiniservConnect beginConnection() {
|
||||||
if(keyPair == null) {
|
if(keyPair == null) {
|
||||||
|
|
@ -74,7 +81,7 @@ public class Client extends AbstractClient implements Runnable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] authenticate(byte[] challenge) {
|
private byte[] authenticate(byte[] challenge) {
|
||||||
try {
|
try {
|
||||||
Mac mac = Mac.getInstance(KeyParameters.MAC_ALGORITHM);
|
Mac mac = Mac.getInstance(KeyParameters.MAC_ALGORITHM);
|
||||||
mac.init(new SecretKeySpec(key, KeyParameters.MAC_ALGORITHM));
|
mac.init(new SecretKeySpec(key, KeyParameters.MAC_ALGORITHM));
|
||||||
|
|
@ -89,25 +96,85 @@ public class Client extends AbstractClient implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(SocketAddress addr) {
|
public void start(SocketAddress addr) {
|
||||||
|
if(getRunning()) {
|
||||||
|
Log.warning("Called Client.start() twice");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
address = addr;
|
address = addr;
|
||||||
|
thread = new Thread(this);
|
||||||
|
thread.setName("MiniServClient");
|
||||||
|
thread.setDaemon(true);
|
||||||
|
|
||||||
|
synchronized(this) {
|
||||||
|
running = true;
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if(getRunning()) {
|
||||||
|
Thread thread = this.thread;
|
||||||
|
synchronized(this) {
|
||||||
|
running = false;
|
||||||
|
|
||||||
|
if(connected)
|
||||||
|
selector.wakeup();
|
||||||
|
}
|
||||||
|
|
||||||
|
while(thread.isAlive()) {
|
||||||
|
try {
|
||||||
|
thread.join();
|
||||||
|
} catch(InterruptedException ex) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.info("Miniserv client stopped");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getRunning() {
|
||||||
|
boolean ret;
|
||||||
|
synchronized(this) {
|
||||||
|
ret = running;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
selector = Selector.open();
|
||||||
socket = SocketChannel.open();
|
socket = SocketChannel.open();
|
||||||
socket.connect(address);
|
socket.connect(address);
|
||||||
socket.configureBlocking(false);
|
socket.configureBlocking(false);
|
||||||
|
|
||||||
selector = Selector.open();
|
selKey = socket.register(selector, SelectionKey.OP_READ);
|
||||||
socket.register(selector, SelectionKey.OP_READ);
|
|
||||||
} catch(IOException ex) {
|
} catch(IOException ex) {
|
||||||
Log.errorEx("Couldn't start client", ex);
|
Log.errorEx("Couldn't start client", ex);
|
||||||
|
|
||||||
|
synchronized(this) {
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(running) {
|
synchronized(this) {
|
||||||
|
connected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.info("Miniserv client connected!");
|
||||||
|
|
||||||
|
OutgoingPacket connPacket = new OutgoingPacket();
|
||||||
|
connPacket.writeByte(PacketID.INIT_CONN.ordinal());
|
||||||
|
connPacket.writeLong(clientUUID.getMostSignificantBits());
|
||||||
|
connPacket.writeLong(clientUUID.getLeastSignificantBits());
|
||||||
|
sendPacket(connPacket);
|
||||||
|
|
||||||
|
while(getRunning()) {
|
||||||
try {
|
try {
|
||||||
unsafeLoop();
|
unsafeLoop();
|
||||||
} catch(Throwable t) {
|
} catch(Throwable t) {
|
||||||
|
|
@ -116,22 +183,51 @@ public class Client extends AbstractClient implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.silentClose(socket);
|
synchronized(this) {
|
||||||
|
connected = false;
|
||||||
|
running = false;
|
||||||
|
authenticated = false;
|
||||||
|
}
|
||||||
|
|
||||||
Util.silentClose(selector);
|
Util.silentClose(selector);
|
||||||
|
Util.silentClose(socket);
|
||||||
|
selector = null;
|
||||||
|
socket = null;
|
||||||
|
|
||||||
|
if(currentTask != null) {
|
||||||
|
currentTask.abort();
|
||||||
|
currentTask.onFinished();
|
||||||
|
currentTask = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized(tasks) {
|
||||||
|
ClientTask task;
|
||||||
|
|
||||||
|
while((task = tasks.poll()) != null) {
|
||||||
|
task.abort();
|
||||||
|
task.onFinished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSendQueue();
|
||||||
|
thread = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unsafeLoop() throws Throwable {
|
private void unsafeLoop() throws Throwable {
|
||||||
selector.select();
|
selector.select();
|
||||||
|
|
||||||
|
if(currentTask == null)
|
||||||
|
nextTask();
|
||||||
|
|
||||||
for(SelectionKey key: selector.selectedKeys()) {
|
for(SelectionKey key: selector.selectedKeys()) {
|
||||||
if(key.isReadable()) {
|
if(key.isReadable()) {
|
||||||
readBuffer.clear();
|
readBuffer.clear();
|
||||||
int rd = socket.read(readBuffer);
|
int rd = socket.read(readBuffer);
|
||||||
|
|
||||||
if(rd <= 0) {
|
if(rd < 0) {
|
||||||
Log.warning("Connection was closed, stopping...");
|
Log.warning("Connection was closed, stopping...");
|
||||||
running = false;
|
running = false;
|
||||||
} else {
|
} else if(rd > 0) {
|
||||||
readBuffer.position(0);
|
readBuffer.position(0);
|
||||||
readBuffer.limit(rd);
|
readBuffer.limit(rd);
|
||||||
readyRead(readBuffer);
|
readyRead(readBuffer);
|
||||||
|
|
@ -156,8 +252,78 @@ public class Client extends AbstractClient implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@PacketHandler(PacketID.AUTHENTICATE)
|
@PacketHandler(PacketID.AUTHENTICATE)
|
||||||
public void handleAuth(DataInputStream dis) {
|
public void handleAuth(DataInputStream dis) throws IOException {
|
||||||
//TODO: Do some stuff
|
int len = dis.readByte();
|
||||||
|
byte[] challenge = new byte[len];
|
||||||
|
dis.readFully(challenge);
|
||||||
|
byte[] mac = authenticate(challenge);
|
||||||
|
|
||||||
|
OutgoingPacket pkt = new OutgoingPacket();
|
||||||
|
pkt.writeByte(PacketID.AUTHENTICATE.ordinal());
|
||||||
|
pkt.writeByte(mac.length);
|
||||||
|
pkt.writeBytes(mac);
|
||||||
|
sendPacket(pkt);
|
||||||
|
|
||||||
|
Log.info("Miniserv client authenticated");
|
||||||
|
|
||||||
|
synchronized(this) {
|
||||||
|
authenticated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PacketHandler(PacketID.BEGIN_FILE_UPLOAD)
|
||||||
|
public void handleBeginUpload(DataInputStream dis) throws IOException {
|
||||||
|
if(currentTask instanceof ClientTaskUploadFile)
|
||||||
|
((ClientTaskUploadFile) currentTask).onReceivedUploadStatus(dis.readByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PacketHandler(PacketID.FILE_STATUS)
|
||||||
|
public void handleFileStatus(DataInputStream dis) throws IOException {
|
||||||
|
if(currentTask instanceof ClientTaskUploadFile)
|
||||||
|
((ClientTaskUploadFile) currentTask).onUploadFinishedStatus(dis.readByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PacketHandler(PacketID.GET_FILE)
|
||||||
|
public void handleGetFile(DataInputStream dis) throws IOException {
|
||||||
|
if(currentTask instanceof ClientTaskGetFile)
|
||||||
|
((ClientTaskGetFile) currentTask).onGetFileResponse(dis.readByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PacketHandler(PacketID.FILE_PART)
|
||||||
|
public void handleFilePart(DataInputStream dis) throws IOException {
|
||||||
|
if(currentTask instanceof ClientTaskGetFile) {
|
||||||
|
int len = dis.readShort() & 0xFFFF;
|
||||||
|
((ClientTaskGetFile) currentTask).onData(getCurrentPacketRawData(), len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nextTask() {
|
||||||
|
if(currentTask != null)
|
||||||
|
currentTask.onFinished();
|
||||||
|
|
||||||
|
synchronized(tasks) {
|
||||||
|
currentTask = tasks.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentTask != null)
|
||||||
|
currentTask.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addTask(ClientTask task) {
|
||||||
|
boolean cancel;
|
||||||
|
synchronized(this) {
|
||||||
|
cancel = !running || !authenticated;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cancel)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
synchronized(tasks) {
|
||||||
|
tasks.offer(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
selector.wakeup();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
27
src/main/java/net/montoyo/wd/miniserv/client/ClientTask.java
Normal file
27
src/main/java/net/montoyo/wd/miniserv/client/ClientTask.java
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.miniserv.client;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public abstract class ClientTask {
|
||||||
|
|
||||||
|
private Consumer<ClientTask> finishCallback;
|
||||||
|
protected final Client client = Client.getInstance();
|
||||||
|
|
||||||
|
public abstract void start();
|
||||||
|
public abstract void abort();
|
||||||
|
|
||||||
|
public void onFinished() {
|
||||||
|
//Called by Client, don't call it from a ClientTask!
|
||||||
|
if(finishCallback != null)
|
||||||
|
finishCallback.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFinishCallback(Consumer<ClientTask> finishCallback) {
|
||||||
|
this.finishCallback = finishCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.miniserv.client;
|
||||||
|
|
||||||
|
import net.montoyo.wd.miniserv.Constants;
|
||||||
|
import net.montoyo.wd.miniserv.OutgoingPacket;
|
||||||
|
import net.montoyo.wd.miniserv.PacketID;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.locks.Condition;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
public class ClientTaskGetFile extends ClientTask {
|
||||||
|
|
||||||
|
private final UUID uuid;
|
||||||
|
private final String fname;
|
||||||
|
|
||||||
|
private int response;
|
||||||
|
private boolean hasResponse;
|
||||||
|
private final ReentrantLock responseLock = new ReentrantLock();
|
||||||
|
private final Condition gotResponse = responseLock.newCondition();
|
||||||
|
|
||||||
|
private final ReentrantLock dataLock = new ReentrantLock();
|
||||||
|
private final Condition dataChanged = dataLock.newCondition();
|
||||||
|
private byte[] data;
|
||||||
|
private int dataLen;
|
||||||
|
|
||||||
|
public ClientTaskGetFile(UUID id, String name) {
|
||||||
|
uuid = id;
|
||||||
|
fname = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
OutgoingPacket pkt = new OutgoingPacket();
|
||||||
|
pkt.writeByte(PacketID.GET_FILE.ordinal());
|
||||||
|
pkt.writeLong(uuid.getMostSignificantBits());
|
||||||
|
pkt.writeLong(uuid.getLeastSignificantBits());
|
||||||
|
pkt.writeString(fname);
|
||||||
|
|
||||||
|
client.sendPacket(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void abort() {
|
||||||
|
responseLock.lock();
|
||||||
|
if(!hasResponse) {
|
||||||
|
response = Constants.GETF_STATUS_CONNECTION_LOST;
|
||||||
|
hasResponse = true;
|
||||||
|
gotResponse.signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
responseLock.unlock();
|
||||||
|
onData(new byte[0], -1); //This will trigger an error
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onGetFileResponse(int status) {
|
||||||
|
boolean triggerError = false;
|
||||||
|
responseLock.lock();
|
||||||
|
|
||||||
|
if(hasResponse) {
|
||||||
|
if(status != 0)
|
||||||
|
triggerError = true;
|
||||||
|
} else {
|
||||||
|
response = status;
|
||||||
|
hasResponse = true;
|
||||||
|
gotResponse.signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
responseLock.unlock();
|
||||||
|
|
||||||
|
if(triggerError)
|
||||||
|
onData(new byte[0], -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int waitForResponse() {
|
||||||
|
responseLock.lock();
|
||||||
|
while(!hasResponse) {
|
||||||
|
try {
|
||||||
|
gotResponse.await();
|
||||||
|
} catch(InterruptedException ex) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
responseLock.unlock();
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onData(byte[] data, int len) {
|
||||||
|
dataLock.lock();
|
||||||
|
while(this.data != null) {
|
||||||
|
try {
|
||||||
|
dataChanged.await();
|
||||||
|
} catch(InterruptedException ex) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.data = data;
|
||||||
|
dataLen = len;
|
||||||
|
dataChanged.signal();
|
||||||
|
dataLock.unlock();
|
||||||
|
|
||||||
|
if(len <= 0)
|
||||||
|
client.nextTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] waitForData() {
|
||||||
|
dataLock.lock();
|
||||||
|
while(this.data == null) {
|
||||||
|
try {
|
||||||
|
dataChanged.await();
|
||||||
|
} catch(InterruptedException ex) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataLock.unlock(); //This won't change until data is null again
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDataLength() {
|
||||||
|
return dataLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nextData() {
|
||||||
|
dataLock.lock();
|
||||||
|
data = null;
|
||||||
|
dataChanged.signal();
|
||||||
|
dataLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileName() {
|
||||||
|
return fname;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.miniserv.client;
|
||||||
|
|
||||||
|
import net.montoyo.wd.miniserv.Constants;
|
||||||
|
import net.montoyo.wd.miniserv.OutgoingPacket;
|
||||||
|
import net.montoyo.wd.miniserv.PacketID;
|
||||||
|
import net.montoyo.wd.utilities.Log;
|
||||||
|
import net.montoyo.wd.utilities.Util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class ClientTaskUploadFile extends ClientTask implements Consumer<OutgoingPacket> {
|
||||||
|
|
||||||
|
private static final byte[] UPLOAD_BUFFER = new byte[65536];
|
||||||
|
|
||||||
|
private final File file;
|
||||||
|
private final long size;
|
||||||
|
private FileInputStream fis;
|
||||||
|
private boolean abortFupa;
|
||||||
|
private int uploadStatus;
|
||||||
|
|
||||||
|
public ClientTaskUploadFile(File fle) throws IOException {
|
||||||
|
file = fle;
|
||||||
|
size = Files.size(fle.toPath());
|
||||||
|
fis = new FileInputStream(fle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
OutgoingPacket pkt = new OutgoingPacket();
|
||||||
|
pkt.writeByte(PacketID.BEGIN_FILE_UPLOAD.ordinal());
|
||||||
|
pkt.writeString(file.getName());
|
||||||
|
pkt.writeLong(size);
|
||||||
|
|
||||||
|
client.sendPacket(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void abort() {
|
||||||
|
abortFupa = true;
|
||||||
|
setUploadStatus(Constants.FUPA_STATUS_CONNECTION_LOST);
|
||||||
|
Util.silentClose(fis);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onReceivedUploadStatus(int status) {
|
||||||
|
if(status == 0) {
|
||||||
|
//Begin upload
|
||||||
|
Log.info("Now uploading %s", file.getName());
|
||||||
|
accept(null);
|
||||||
|
} else {
|
||||||
|
Util.silentClose(fis);
|
||||||
|
setUploadStatus(status);
|
||||||
|
client.nextTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onUploadFinishedStatus(int status) {
|
||||||
|
abortFupa = true; //This isn't necessary, but just in case...
|
||||||
|
setUploadStatus(status);
|
||||||
|
client.nextTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(OutgoingPacket nocare) {
|
||||||
|
if(abortFupa)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int rd;
|
||||||
|
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
rd = fis.read(UPLOAD_BUFFER);
|
||||||
|
} catch(IOException ex) {
|
||||||
|
Log.warningEx("Caught IOException while sending some file", ex);
|
||||||
|
rd = 0; //This will cause a FUPA_STATUS_USER_ABORT
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(rd == 0);
|
||||||
|
|
||||||
|
if(rd >= 0) { //If rd < 0, end of file, we're done.
|
||||||
|
OutgoingPacket pkt = new OutgoingPacket();
|
||||||
|
pkt.writeByte(PacketID.FILE_PART.ordinal());
|
||||||
|
pkt.writeShort(rd);
|
||||||
|
pkt.writeBytes(UPLOAD_BUFFER, 0, rd);
|
||||||
|
client.sendPacket(pkt);
|
||||||
|
|
||||||
|
if(rd > 0) {
|
||||||
|
pkt.setOnFinishAction(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Util.silentClose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUploadStatus(int val) {
|
||||||
|
synchronized(this) {
|
||||||
|
uploadStatus = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUploadStatus() {
|
||||||
|
int ret;
|
||||||
|
synchronized(this) {
|
||||||
|
ret = uploadStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -42,7 +42,11 @@ public class ClientManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getClientKey(UUID uuid) {
|
public byte[] getClientKey(UUID uuid) {
|
||||||
return keys.get(uuid);
|
keyLock.readLock().lock();
|
||||||
|
byte[] ret = keys.get(uuid);
|
||||||
|
keyLock.readLock().unlock();
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void revokeClientKey(UUID id) {
|
public void revokeClientKey(UUID id) {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import java.nio.channels.SocketChannel;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class Server extends Thread {
|
public class Server implements Runnable {
|
||||||
|
|
||||||
private static Server instance;
|
private static Server instance;
|
||||||
|
|
||||||
|
|
@ -37,40 +37,97 @@ public class Server extends Thread {
|
||||||
private final ClientManager clientMgr = new ClientManager();
|
private final ClientManager clientMgr = new ClientManager();
|
||||||
private File directory;
|
private File directory;
|
||||||
private long maxQuota = 1024 * 1024; //1 MiB max
|
private long maxQuota = 1024 * 1024; //1 MiB max
|
||||||
|
private volatile boolean running;
|
||||||
|
private volatile Thread thread;
|
||||||
|
|
||||||
public Server() {
|
|
||||||
setDaemon(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start() {
|
public void start() {
|
||||||
|
thread = new Thread(this);
|
||||||
|
thread.setName("MiniServServer");
|
||||||
|
thread.setDaemon(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
server = ServerSocketChannel.open();
|
server = ServerSocketChannel.open();
|
||||||
server.bind(new InetSocketAddress(port));
|
server.bind(new InetSocketAddress(port));
|
||||||
server.configureBlocking(false);
|
server.configureBlocking(false);
|
||||||
|
} catch(Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
Util.silentClose(server);
|
||||||
|
server = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
selector = Selector.open();
|
selector = Selector.open();
|
||||||
server.register(selector, SelectionKey.OP_ACCEPT);
|
server.register(selector, SelectionKey.OP_ACCEPT);
|
||||||
} catch(Throwable t) {
|
} catch(Throwable t) {
|
||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
|
Util.silentClose(selector);
|
||||||
|
Util.silentClose(server);
|
||||||
|
selector = null;
|
||||||
|
server = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
super.start();
|
synchronized(this) {
|
||||||
|
running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopServer() {
|
||||||
|
if(getRunning()) {
|
||||||
|
Thread thread = this.thread;
|
||||||
|
|
||||||
|
synchronized(this) {
|
||||||
|
running = false;
|
||||||
|
selector.wakeup();
|
||||||
|
}
|
||||||
|
|
||||||
|
while(thread.isAlive()) {
|
||||||
|
try {
|
||||||
|
thread.join();
|
||||||
|
} catch(InterruptedException ex) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.info("Miniserv server stopped");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getRunning() {
|
||||||
|
boolean ret;
|
||||||
|
synchronized(this) {
|
||||||
|
ret = running;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
boolean running = true;
|
while(getRunning()) {
|
||||||
|
|
||||||
while(running) {
|
|
||||||
try {
|
try {
|
||||||
loopUnsafe();
|
loopUnsafe();
|
||||||
} catch(Throwable t) {
|
} catch(Throwable t) {
|
||||||
t.printStackTrace();
|
Log.errorEx("Miniserv Server crashed", t);
|
||||||
running = false;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
synchronized(this) {
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(ServerClient cli: clientList)
|
||||||
|
Util.silentClose(cli.getChannel());
|
||||||
|
|
||||||
|
clientList.clear();
|
||||||
|
clientMap.clear();
|
||||||
|
Util.silentClose(selector);
|
||||||
|
Util.silentClose(server);
|
||||||
|
selector = null;
|
||||||
|
server = null;
|
||||||
|
thread = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loopUnsafe() throws Throwable {
|
private void loopUnsafe() throws Throwable {
|
||||||
|
|
@ -89,9 +146,8 @@ public class Server extends Thread {
|
||||||
|
|
||||||
if(chan != null) {
|
if(chan != null) {
|
||||||
chan.configureBlocking(false);
|
chan.configureBlocking(false);
|
||||||
chan.register(selector, SelectionKey.OP_READ);
|
|
||||||
|
|
||||||
ServerClient toAdd = new ServerClient(chan, selector);
|
ServerClient toAdd = new ServerClient(chan, selector);
|
||||||
|
|
||||||
clientMap.put(chan, toAdd);
|
clientMap.put(chan, toAdd);
|
||||||
clientList.add(toAdd);
|
clientList.add(toAdd);
|
||||||
toAdd.onConnect();
|
toAdd.onConnect();
|
||||||
|
|
@ -110,7 +166,7 @@ public class Server extends Thread {
|
||||||
|
|
||||||
if(read < 0)
|
if(read < 0)
|
||||||
cli.setShouldRemove(); //End of stream
|
cli.setShouldRemove(); //End of stream
|
||||||
else {
|
else if(read > 0) {
|
||||||
readBuffer.position(0);
|
readBuffer.position(0);
|
||||||
readBuffer.limit(read);
|
readBuffer.limit(read);
|
||||||
cli.readyRead(readBuffer);
|
cli.readyRead(readBuffer);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import net.montoyo.wd.utilities.Log;
|
||||||
import net.montoyo.wd.utilities.Util;
|
import net.montoyo.wd.utilities.Util;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.channels.ClosedChannelException;
|
||||||
|
import java.nio.channels.SelectionKey;
|
||||||
import java.nio.channels.Selector;
|
import java.nio.channels.Selector;
|
||||||
import java.nio.channels.SocketChannel;
|
import java.nio.channels.SocketChannel;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
@ -32,6 +34,10 @@ public class ServerClient extends AbstractClient {
|
||||||
ServerClient(SocketChannel s, Selector ss) {
|
ServerClient(SocketChannel s, Selector ss) {
|
||||||
socket = s;
|
socket = s;
|
||||||
selector = ss;
|
selector = ss;
|
||||||
|
|
||||||
|
try {
|
||||||
|
selKey = socket.register(selector, SelectionKey.OP_READ);
|
||||||
|
} catch(ClosedChannelException ex) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -92,6 +98,7 @@ public class ServerClient extends AbstractClient {
|
||||||
|
|
||||||
int len = dis.readByte() & 0xFF;
|
int len = dis.readByte() & 0xFF;
|
||||||
byte[] mac = new byte[len];
|
byte[] mac = new byte[len];
|
||||||
|
dis.readFully(mac);
|
||||||
|
|
||||||
if(Server.getInstance().getClientManager().verifyClient(uuid, challenge, mac)) {
|
if(Server.getInstance().getClientManager().verifyClient(uuid, challenge, mac)) {
|
||||||
Log.info("Client with UUID %s authenticated successfully", uuid.toString());
|
Log.info("Client with UUID %s authenticated successfully", uuid.toString());
|
||||||
|
|
@ -136,21 +143,21 @@ public class ServerClient extends AbstractClient {
|
||||||
OutgoingPacket rep = new OutgoingPacket();
|
OutgoingPacket rep = new OutgoingPacket();
|
||||||
rep.writeByte(PacketID.BEGIN_FILE_UPLOAD.ordinal());
|
rep.writeByte(PacketID.BEGIN_FILE_UPLOAD.ordinal());
|
||||||
|
|
||||||
if(isFileNameInvalid(fname)) {
|
if(Util.isFileNameInvalid(fname)) {
|
||||||
Log.warning("Client %s tried to upload a file with a bad name", uuid.toString());
|
Log.warning("Client %s tried to upload a file with a bad name", uuid.toString());
|
||||||
rep.writeByte(1);
|
rep.writeByte(Constants.FUPA_STATUS_BAD_NAME);
|
||||||
} else if(size <= 0) {
|
} else if(size <= 0) {
|
||||||
Log.warning("Client %s tried to upload a file an invalid size", uuid.toString());
|
Log.warning("Client %s tried to upload a file an invalid size", uuid.toString());
|
||||||
rep.writeByte(2);
|
rep.writeByte(Constants.FUPA_STATUS_INVALID_SIZE);
|
||||||
} else if(quota + size > Server.getInstance().getMaxQuota())
|
} else if(quota + size > Server.getInstance().getMaxQuota())
|
||||||
rep.writeByte(3);
|
rep.writeByte(Constants.FUPA_STATUS_EXCEEDS_QUOTA);
|
||||||
else if(currentFile != null || sendingFile)
|
else if(currentFile != null || sendingFile)
|
||||||
rep.writeByte(4);
|
rep.writeByte(Constants.FUPA_STATUS_OCCUPIED);
|
||||||
else {
|
else {
|
||||||
File fle = new File(userDir, fname);
|
File fle = new File(userDir, fname);
|
||||||
|
|
||||||
if(fle.exists())
|
if(fle.exists())
|
||||||
rep.writeByte(5);
|
rep.writeByte(Constants.FUPA_STATUS_FILE_EXISTS);
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
currentFile = new FileOutputStream(fle);
|
currentFile = new FileOutputStream(fle);
|
||||||
|
|
@ -160,7 +167,7 @@ public class ServerClient extends AbstractClient {
|
||||||
rep.writeByte(0); //OK
|
rep.writeByte(0); //OK
|
||||||
} catch(IOException ex) {
|
} catch(IOException ex) {
|
||||||
Log.warningEx("IOException while uploading file %s from user %s", ex, fname, uuid.toString());
|
Log.warningEx("IOException while uploading file %s from user %s", ex, fname, uuid.toString());
|
||||||
rep.writeByte(6);
|
rep.writeByte(Constants.FUPA_STATUS_INTERNAL_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -175,14 +182,14 @@ public class ServerClient extends AbstractClient {
|
||||||
int len = dis.readShort() & 0xFFFF;
|
int len = dis.readShort() & 0xFFFF;
|
||||||
if(len <= 0) {
|
if(len <= 0) {
|
||||||
//Aborted by user
|
//Aborted by user
|
||||||
finishUpload(1);
|
finishUpload(Constants.FUPA_STATUS_USER_ABORT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentFileSize += (long) len;
|
currentFileSize += (long) len;
|
||||||
if(currentFileSize > currentFileExpectedSize) {
|
if(currentFileSize > currentFileExpectedSize) {
|
||||||
//Exceeded expected size
|
//Exceeded expected size
|
||||||
finishUpload(2);
|
finishUpload(Constants.FUPA_STATUS_LIER);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,7 +197,7 @@ public class ServerClient extends AbstractClient {
|
||||||
currentFile.write(getCurrentPacketRawData(), 3, len);
|
currentFile.write(getCurrentPacketRawData(), 3, len);
|
||||||
} catch(IOException ex) {
|
} catch(IOException ex) {
|
||||||
Log.warningEx("Client %s encountered an IOException while uploading some file", ex, uuid.toString());
|
Log.warningEx("Client %s encountered an IOException while uploading some file", ex, uuid.toString());
|
||||||
finishUpload(3);
|
finishUpload(Constants.FUPA_STATUS_INTERNAL_ERROR);
|
||||||
currentFileSize -= (long) len;
|
currentFileSize -= (long) len;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -210,8 +217,8 @@ public class ServerClient extends AbstractClient {
|
||||||
OutgoingPacket rep = new OutgoingPacket();
|
OutgoingPacket rep = new OutgoingPacket();
|
||||||
rep.writeByte(PacketID.GET_FILE.ordinal());
|
rep.writeByte(PacketID.GET_FILE.ordinal());
|
||||||
|
|
||||||
if(isFileNameInvalid(fname))
|
if(Util.isFileNameInvalid(fname))
|
||||||
rep.writeByte(1);
|
rep.writeByte(Constants.GETF_STATUS_BAD_NAME);
|
||||||
else {
|
else {
|
||||||
UUID user = new UUID(msb, lsb);
|
UUID user = new UUID(msb, lsb);
|
||||||
File fle = new File(Server.getInstance().getDirectory(), user.toString() + File.separatorChar + fname);
|
File fle = new File(Server.getInstance().getDirectory(), user.toString() + File.separatorChar + fname);
|
||||||
|
|
@ -220,7 +227,7 @@ public class ServerClient extends AbstractClient {
|
||||||
rep.setOnFinishAction(new SendFileCallback(fle));
|
rep.setOnFinishAction(new SendFileCallback(fle));
|
||||||
sendingFile = true;
|
sendingFile = true;
|
||||||
} catch(FileNotFoundException ex) {
|
} catch(FileNotFoundException ex) {
|
||||||
rep.writeByte(2);
|
rep.writeByte(Constants.GETF_STATUS_NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,10 +235,6 @@ public class ServerClient extends AbstractClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isFileNameInvalid(String fname) {
|
|
||||||
return fname.isEmpty() || fname.length() > 64 || fname.charAt(0) == '.' || fname.indexOf('/') >= 0 || fname.indexOf('\\') >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void finishUpload(int status) {
|
private void finishUpload(int status) {
|
||||||
if(currentFile != null) {
|
if(currentFile != null) {
|
||||||
OutgoingPacket pkt = new OutgoingPacket();
|
OutgoingPacket pkt = new OutgoingPacket();
|
||||||
|
|
@ -274,7 +277,7 @@ public class ServerClient extends AbstractClient {
|
||||||
|
|
||||||
OutgoingPacket pkt = new OutgoingPacket();
|
OutgoingPacket pkt = new OutgoingPacket();
|
||||||
pkt.writeByte(PacketID.GET_FILE.ordinal());
|
pkt.writeByte(PacketID.GET_FILE.ordinal());
|
||||||
pkt.writeByte(3); //Read error
|
pkt.writeByte(Constants.GETF_STATUS_INTERNAL_ERROR); //Read error
|
||||||
sendPacket(pkt);
|
sendPacket(pkt);
|
||||||
|
|
||||||
Util.silentClose(fis);
|
Util.silentClose(fis);
|
||||||
|
|
@ -292,7 +295,7 @@ public class ServerClient extends AbstractClient {
|
||||||
|
|
||||||
pkt.writeByte(PacketID.FILE_PART.ordinal());
|
pkt.writeByte(PacketID.FILE_PART.ordinal());
|
||||||
pkt.writeShort(rd);
|
pkt.writeShort(rd);
|
||||||
pkt.writeBytes(FILE_UPLOAD_BUFFER);
|
pkt.writeBytes(FILE_UPLOAD_BUFFER, 0, rd);
|
||||||
sendPacket(pkt);
|
sendPacket(pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,13 @@ package net.montoyo.wd.net;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
|
|
||||||
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.miniserv.client.Client;
|
||||||
|
import net.montoyo.wd.utilities.Log;
|
||||||
|
|
||||||
@Message(messageId = 11, side = Side.CLIENT)
|
@Message(messageId = 11, side = Side.CLIENT)
|
||||||
public class CMessageMiniservKey implements IMessage {
|
public class CMessageMiniservKey implements IMessage, Runnable {
|
||||||
|
|
||||||
private byte[] encryptedKey;
|
private byte[] encryptedKey;
|
||||||
|
|
||||||
|
|
@ -24,24 +25,22 @@ public class CMessageMiniservKey implements IMessage {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fromBytes(ByteBuf buf) {
|
public void fromBytes(ByteBuf buf) {
|
||||||
encryptedKey = new byte[buf.readByte() & 0xFF];
|
encryptedKey = new byte[buf.readShort() & 0xFFFF];
|
||||||
buf.readBytes(encryptedKey);
|
buf.readBytes(encryptedKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void toBytes(ByteBuf buf) {
|
public void toBytes(ByteBuf buf) {
|
||||||
buf.writeByte(encryptedKey.length);
|
buf.writeShort(encryptedKey.length);
|
||||||
buf.writeBytes(encryptedKey);
|
buf.writeBytes(encryptedKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Handler implements IMessageHandler<CMessageMiniservKey, IMessage> {
|
@Override
|
||||||
|
public void run() {
|
||||||
@Override
|
if(Client.getInstance().decryptKey(encryptedKey)) {
|
||||||
public IMessage onMessage(CMessageMiniservKey message, MessageContext ctx) {
|
Log.info("Successfully received and decrypted key, starting miniserv client...");
|
||||||
//TODO: Start client thread
|
WebDisplays.PROXY.startMiniServClient();
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
43
src/main/java/net/montoyo/wd/net/CMessageServerInfo.java
Normal file
43
src/main/java/net/montoyo/wd/net/CMessageServerInfo.java
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 BARBOTIN Nicolas
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.montoyo.wd.net;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||||
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
|
import net.montoyo.wd.WebDisplays;
|
||||||
|
import net.montoyo.wd.miniserv.client.Client;
|
||||||
|
|
||||||
|
@Message(messageId = 12, side = Side.CLIENT)
|
||||||
|
public class CMessageServerInfo implements IMessage, Runnable {
|
||||||
|
|
||||||
|
private int miniservPort;
|
||||||
|
|
||||||
|
public CMessageServerInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public CMessageServerInfo(int msPort) {
|
||||||
|
miniservPort = msPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fromBytes(ByteBuf buf) {
|
||||||
|
miniservPort = buf.readShort() & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toBytes(ByteBuf buf) {
|
||||||
|
buf.writeShort(miniservPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
WebDisplays.PROXY.setMiniservClientPort(miniservPort);
|
||||||
|
|
||||||
|
if(miniservPort > 0)
|
||||||
|
WebDisplays.NET_HANDLER.sendToServer(Client.getInstance().beginConnection());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -29,6 +29,7 @@ public abstract class Messages {
|
||||||
l.add(CMessageJSResponse.class);
|
l.add(CMessageJSResponse.class);
|
||||||
l.add(SMessageMiniservConnect.class);
|
l.add(SMessageMiniservConnect.class);
|
||||||
l.add(CMessageMiniservKey.class);
|
l.add(CMessageMiniservKey.class);
|
||||||
|
l.add(CMessageServerInfo.class);
|
||||||
|
|
||||||
messages = l.toArray(new Class[0]);
|
messages = l.toArray(new Class[0]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
|
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
|
||||||
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
|
import net.montoyo.wd.miniserv.server.ClientManager;
|
||||||
|
import net.montoyo.wd.miniserv.server.Server;
|
||||||
|
|
||||||
@Message(messageId = 10, side = Side.SERVER)
|
@Message(messageId = 10, side = Side.SERVER)
|
||||||
public class SMessageMiniservConnect implements IMessage {
|
public class SMessageMiniservConnect implements IMessage {
|
||||||
|
|
@ -26,29 +28,31 @@ public class SMessageMiniservConnect implements IMessage {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fromBytes(ByteBuf buf) {
|
public void fromBytes(ByteBuf buf) {
|
||||||
int sz = buf.readByte() & 0xFF;
|
int sz = buf.readShort() & 0xFFFF;
|
||||||
modulus = new byte[sz];
|
modulus = new byte[sz];
|
||||||
buf.readBytes(modulus);
|
buf.readBytes(modulus);
|
||||||
|
|
||||||
sz = buf.readByte() & 0xFF;
|
sz = buf.readShort() & 0xFFFF;
|
||||||
exponent = new byte[sz];
|
exponent = new byte[sz];
|
||||||
buf.readBytes(exponent);
|
buf.readBytes(exponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void toBytes(ByteBuf buf) {
|
public void toBytes(ByteBuf buf) {
|
||||||
buf.writeByte(modulus.length);
|
buf.writeShort(modulus.length);
|
||||||
buf.writeBytes(modulus);
|
buf.writeBytes(modulus);
|
||||||
buf.writeByte(exponent.length);
|
buf.writeShort(exponent.length);
|
||||||
buf.writeBytes(exponent);
|
buf.writeBytes(exponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Handler implements IMessageHandler<SMessageMiniservConnect, IMessage> {
|
public static class Handler implements IMessageHandler<SMessageMiniservConnect, IMessage> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IMessage onMessage(SMessageMiniservConnect message, MessageContext ctx) {
|
public IMessage onMessage(SMessageMiniservConnect msg, MessageContext ctx) {
|
||||||
//TODO: Generate key
|
ClientManager cliMgr = Server.getInstance().getClientManager();
|
||||||
return null;
|
byte[] encKey = cliMgr.encryptClientKey(ctx.getServerHandler().player.getGameProfile().getId(), msg.modulus, msg.exponent);
|
||||||
|
|
||||||
|
return encKey == null ? null : new CMessageMiniservKey(encKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -224,4 +224,7 @@ public abstract class Util {
|
||||||
return str.contains("://") ? str : ("http://" + str);
|
return str.contains("://") ? str : ("http://" + str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isFileNameInvalid(String fname) {
|
||||||
|
return fname.isEmpty() || fname.length() > 64 || fname.charAt(0) == '.' || fname.indexOf('/') >= 0 || fname.indexOf('\\') >= 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user