mirror of
https://bitbucket.org/projectswg/packet-master.git
synced 2026-01-16 23:04:26 -05:00
Updated a lot of stuff
This commit is contained in:
6
src/com/projectswg/ItemSelectedCallback.java
Normal file
6
src/com/projectswg/ItemSelectedCallback.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package com.projectswg;
|
||||
|
||||
public interface ItemSelectedCallback {
|
||||
void onPacketSelected(int index);
|
||||
void onObjectSelected(long objectId);
|
||||
}
|
||||
6
src/com/projectswg/LeftPanelContent.java
Normal file
6
src/com/projectswg/LeftPanelContent.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package com.projectswg;
|
||||
|
||||
public enum LeftPanelContent {
|
||||
PACKETS,
|
||||
OBJECTS
|
||||
}
|
||||
@@ -2,17 +2,16 @@ package com.projectswg;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Date;
|
||||
|
||||
import com.projectswg.layout.AnalysisPanel;
|
||||
import com.projectswg.layout.LayoutLoader;
|
||||
import com.projectswg.layout.PacketPanel;
|
||||
import com.projectswg.layout.ToolbarPanel;
|
||||
import com.projectswg.packets.PacketData;
|
||||
import com.projectswg.packets.PacketInterface;
|
||||
import com.projectswg.packets.PacketInterface.InterfacePacket;
|
||||
import com.projectswg.packets.PacketInterface.PacketInterfaceCallback;
|
||||
import com.projectswg.packets.PacketProcessor;
|
||||
import com.projectswg.packets.PacketProcessor.CrcChangedException;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.geometry.VPos;
|
||||
@@ -33,7 +32,7 @@ public class PacketMaster extends Application implements PacketInterfaceCallback
|
||||
|
||||
private Stage stage;
|
||||
|
||||
private PacketData packetData;
|
||||
private PacketMasterData packetMasterData;
|
||||
private PacketInterface packetInterface;
|
||||
private PacketProcessor packetProcessor;
|
||||
|
||||
@@ -56,14 +55,14 @@ public class PacketMaster extends Application implements PacketInterfaceCallback
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
super.init();
|
||||
packetData = new PacketData();
|
||||
packetMasterData = new PacketMasterData();
|
||||
packetInterface = new PacketInterface();
|
||||
packetProcessor = new PacketProcessor(packetData);
|
||||
packetProcessor = new PacketProcessor(packetMasterData);
|
||||
|
||||
packetInterface.setCallback(this);
|
||||
toolbarPanel = new ToolbarPanel(packetData);
|
||||
packetPanel = new PacketPanel(packetData);
|
||||
analysisPanel = new AnalysisPanel(packetData);
|
||||
toolbarPanel = new ToolbarPanel(packetMasterData);
|
||||
packetPanel = new PacketPanel(packetMasterData);
|
||||
analysisPanel = new AnalysisPanel(packetMasterData);
|
||||
packetPanel.setPacketSelectedCallback(analysisPanel);
|
||||
toolbarPanel.addPacketSelectedCallback(analysisPanel);
|
||||
toolbarPanel.addPacketSelectedCallback(packetPanel);
|
||||
@@ -173,18 +172,27 @@ public class PacketMaster extends Application implements PacketInterfaceCallback
|
||||
|
||||
@Override
|
||||
public void onCaptureStarted() {
|
||||
packetData.clear();
|
||||
packetMasterData.getData().clear();
|
||||
packetProcessor.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacket(InetAddress addr, int source, int destination, Date time, byte [] data) {
|
||||
packetProcessor.onPacket(addr, time, data, packetData.isClient(addr) ? source : destination);
|
||||
public void onPacket(InterfacePacket packet) {
|
||||
try {
|
||||
packetProcessor.onPacket(packet);
|
||||
} catch (CrcChangedException e) {
|
||||
if (!packetInterface.isLive()) {
|
||||
packetInterface.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureFinished() {
|
||||
// gui.repaint();
|
||||
packetProcessor.onCaptureFinished();
|
||||
packetPanel.updatePackets();
|
||||
packetPanel.updateObjects();
|
||||
}
|
||||
|
||||
public void openFile(String file) {
|
||||
|
||||
50
src/com/projectswg/PacketMasterData.java
Normal file
50
src/com/projectswg/PacketMasterData.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package com.projectswg;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import com.projectswg.packets.PacketData;
|
||||
|
||||
public class PacketMasterData {
|
||||
|
||||
private final AtomicReference<LeftPanelContent> leftPanel;
|
||||
private final AtomicBoolean searchSoe;
|
||||
private final AtomicBoolean searchSwg;
|
||||
private final PacketData data;
|
||||
|
||||
public PacketMasterData() {
|
||||
leftPanel = new AtomicReference<>(LeftPanelContent.PACKETS);
|
||||
searchSoe = new AtomicBoolean(false);
|
||||
searchSwg = new AtomicBoolean(true);
|
||||
data = new PacketData();
|
||||
}
|
||||
|
||||
public PacketData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setLeftPanelContent(LeftPanelContent content) {
|
||||
leftPanel.set(content);
|
||||
}
|
||||
|
||||
public LeftPanelContent getLeftPanelContent() {
|
||||
return leftPanel.get();
|
||||
}
|
||||
|
||||
public void setSearchSoe(boolean searchSoe) {
|
||||
this.searchSoe.set(searchSoe);
|
||||
}
|
||||
|
||||
public boolean isSearchSoe() {
|
||||
return searchSoe.get();
|
||||
}
|
||||
|
||||
public void setSearchSwg(boolean searchSwg) {
|
||||
this.searchSwg.set(searchSwg);
|
||||
}
|
||||
|
||||
public boolean isSearchSwg() {
|
||||
return searchSwg.get();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.projectswg;
|
||||
|
||||
public interface PacketSelectedCallback {
|
||||
void onPacketSelected(int index);
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import resources.encodables.Encodable;
|
||||
|
||||
import com.sun.org.apache.xerces.internal.parsers.DOMParser;
|
||||
|
||||
import network.packets.Packet;
|
||||
import com.projectswg.network.packets.Packet;
|
||||
import network.packets.swg.zone.baselines.Baseline.BaselineType;
|
||||
|
||||
public class BaselineProcessor {
|
||||
@@ -91,15 +91,15 @@ public class BaselineProcessor {
|
||||
int pos = data.position();
|
||||
data.get(extra);
|
||||
data.position(pos);
|
||||
int len = Packet.getInt(data);
|
||||
int size = Packet.getInt(data);
|
||||
Packet.getInt(data); // updates
|
||||
StringBuilder bldr = new StringBuilder();
|
||||
for (int i = 0; i < len; i++) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i > 0)
|
||||
bldr.append(", ");
|
||||
bldr.append(processVariable(data, subType));
|
||||
}
|
||||
return type + " " + bldr.toString();
|
||||
return type + " ["+size+"] " + bldr.toString();
|
||||
} else if (type.startsWith("SWGMap")) {
|
||||
String [] subTypes = type.substring(type.indexOf(':')+1).split(",", 2);
|
||||
byte[] extra = new byte[data.remaining()];
|
||||
@@ -119,7 +119,7 @@ public class BaselineProcessor {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return type + " " + bldr.toString();
|
||||
return type + " ["+size+"] " + bldr.toString();
|
||||
}
|
||||
try {
|
||||
Object o = Class.forName(type).newInstance();
|
||||
|
||||
@@ -4,11 +4,12 @@ import java.nio.ByteBuffer;
|
||||
import java.util.Date;
|
||||
|
||||
import network.PacketType;
|
||||
import network.packets.Packet;
|
||||
import network.packets.swg.SWGPacket;
|
||||
|
||||
public class GUIPacket {
|
||||
|
||||
private SWGPacket packet;
|
||||
private Packet packet;
|
||||
private PacketType type;
|
||||
private ByteBuffer data;
|
||||
private Date time;
|
||||
@@ -32,19 +33,18 @@ public class GUIPacket {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public GUIPacket(ByteBuffer data, Date time, int soeOpcode, int port, boolean client) {
|
||||
this.data = data;
|
||||
public GUIPacket(Packet packet, Date time, int soeOpcode, int port, boolean client) {
|
||||
this.packet = packet;
|
||||
this.data = packet.getData();
|
||||
this.soeOpcode = soeOpcode;
|
||||
this.client = client;
|
||||
this.time = time;
|
||||
this.port = port;
|
||||
|
||||
this.packet = null;
|
||||
this.type = null;
|
||||
this.swgOpcode = 0;
|
||||
}
|
||||
|
||||
public SWGPacket getPacket() { return packet; }
|
||||
public Packet getPacket() { return packet; }
|
||||
public PacketType getType() { return type; }
|
||||
public ByteBuffer getData() { return data; }
|
||||
public Date getTime() { return time; }
|
||||
@@ -52,7 +52,7 @@ public class GUIPacket {
|
||||
public int getSWGOpcode() { return swgOpcode; }
|
||||
public int getSOEOpcode() { return soeOpcode; }
|
||||
public boolean isClient() { return client; }
|
||||
public boolean isSWGPacket() { return packet != null; }
|
||||
public boolean isSWGPacket() { return swgOpcode != 0; }
|
||||
|
||||
public String toString() {
|
||||
String packetName = getStringForSOEOpcode(soeOpcode);
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package com.projectswg.layout;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Map.Entry;
|
||||
@@ -18,7 +22,12 @@ import network.packets.swg.zone.deltas.DeltasMessage;
|
||||
|
||||
import org.jnetpcap.nio.JBuffer;
|
||||
|
||||
import com.projectswg.PacketSelectedCallback;
|
||||
import resources.network.BaselineObject;
|
||||
import resources.objects.SWGObject;
|
||||
import resources.server_info.CrcDatabase;
|
||||
|
||||
import com.projectswg.ItemSelectedCallback;
|
||||
import com.projectswg.PacketMasterData;
|
||||
import com.projectswg.gui.BaselineProcessor;
|
||||
import com.projectswg.gui.GUIPacket;
|
||||
import com.projectswg.packets.PacketData;
|
||||
@@ -28,17 +37,19 @@ import javafx.geometry.Insets;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.layout.Pane;
|
||||
|
||||
public class AnalysisPanel extends Pane implements Initializable, PacketSelectedCallback {
|
||||
public class AnalysisPanel extends Pane implements Initializable, ItemSelectedCallback {
|
||||
|
||||
private final PacketData packetData;
|
||||
private final CrcDatabase crcDatabase;
|
||||
|
||||
private DateFormat dateFormat;
|
||||
private GUIPacket packet;
|
||||
private TextArea packetDisplay;
|
||||
|
||||
public AnalysisPanel(PacketData data) {
|
||||
this.packetData = data;
|
||||
dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSS z");;
|
||||
public AnalysisPanel(PacketMasterData data) {
|
||||
this.packetData = data.getData();
|
||||
this.crcDatabase = new CrcDatabase();
|
||||
dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSS z");
|
||||
LayoutLoader.load("AnalysisPanel.fxml", this, this);
|
||||
}
|
||||
|
||||
@@ -54,19 +65,24 @@ public class AnalysisPanel extends Pane implements Initializable, PacketSelected
|
||||
|
||||
@Override
|
||||
public void onPacketSelected(int index) {
|
||||
setPacket(packetData.get(index));
|
||||
}
|
||||
|
||||
public void setPacket(GUIPacket packet) {
|
||||
this.packet = packet;
|
||||
this.packet = packetData.get(index);
|
||||
StringBuilder str = new StringBuilder();
|
||||
if (packet.getSWGOpcode() != 0)
|
||||
if (packet.getSWGOpcode() != 0 && packet.getPacket() instanceof SWGPacket)
|
||||
drawSWGPacket(str);
|
||||
else
|
||||
drawSOEPacket(str);
|
||||
packetDisplay.setText(str.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onObjectSelected(long objectId) {
|
||||
StringBuilder str = new StringBuilder();
|
||||
SWGObject obj = packetData.getObject(objectId);
|
||||
if (obj != null)
|
||||
drawObject(str, obj, 0);
|
||||
packetDisplay.setText(str.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void layoutChildren() {
|
||||
super.layoutChildren();
|
||||
@@ -74,89 +90,142 @@ public class AnalysisPanel extends Pane implements Initializable, PacketSelected
|
||||
}
|
||||
|
||||
private void drawSWGPacket(StringBuilder str) {
|
||||
SWGPacket packet = this.packet.getPacket();
|
||||
if (!(packet.getPacket() instanceof SWGPacket))
|
||||
return;
|
||||
SWGPacket packet = (SWGPacket) this.packet.getPacket();
|
||||
ByteBuffer data = packet.getData();
|
||||
data.position(0);
|
||||
int line = 0;
|
||||
drawString(str, "Date: " + dateFormat.format(this.packet.getTime()), line++);
|
||||
drawString(str, "Port: " + this.packet.getPort(), line++);
|
||||
drawString(str, "Priority: " + String.format("0x%04X", packet.getOpcode()), line++);
|
||||
drawString(str, "SWG Opcode: " + String.format("0x%08X", packet.getSWGOpcode()).toUpperCase(), line++);
|
||||
drawString(str, "Packet: " + packet.getClass().getSimpleName(), line++);
|
||||
drawString(str, "Date: " + dateFormat.format(this.packet.getTime()));
|
||||
drawString(str, "Source: " + this.packet.getPacket().getAddress() + ":" + this.packet.getPort());
|
||||
drawString(str, "Priority: " + String.format("0x%04X", packet.getOpcode()));
|
||||
drawString(str, "SWG Opcode: " + String.format("0x%08X", packet.getSWGOpcode()).toUpperCase());
|
||||
drawString(str, "Packet: " + packet.getClass().getSimpleName());
|
||||
if (packet instanceof Baseline) {
|
||||
Baseline b = (Baseline) packet;
|
||||
drawString(str, "Type: " + b.getType() + " " + b.getNum(), line++);
|
||||
drawString(str, "Object ID: " + b.getObjectId() + " [" + String.format("%016X", b.getObjectId()) + "]", line++);
|
||||
drawString(str, "Type: " + b.getType() + " " + b.getNum());
|
||||
drawString(str, "Object ID: " + b.getObjectId() + " [" + String.format("%016X", b.getObjectId()) + "]");
|
||||
drawStrings(str, createRaw(data));
|
||||
drawString(str, "");
|
||||
SWGObject obj = packetData.getObject(b.getObjectId());
|
||||
if (obj != null)
|
||||
drawObject(str, obj, 0);
|
||||
else
|
||||
drawString(str, "NULL");
|
||||
return;
|
||||
} else if (packet instanceof DeltasMessage) {
|
||||
DeltasMessage b = (DeltasMessage) packet;
|
||||
drawString(str, "Type: " + b.getType() + " " + b.getNum(), line++);
|
||||
drawString(str, "Object ID: " + b.getObjectId() + " [" + String.format("%016X", b.getObjectId()) + "]", line++);
|
||||
drawString(str, "Type: " + b.getType() + " " + b.getNum());
|
||||
drawString(str, "Object ID: " + b.getObjectId() + " [" + String.format("%016X", b.getObjectId()) + "]");
|
||||
}
|
||||
line = drawStrings(str, createRaw(data), line);
|
||||
drawString(str, "", line++);
|
||||
line = drawObject(str, packet, line, 0);
|
||||
drawStrings(str, createRaw(data));
|
||||
drawString(str, "");
|
||||
if (packet != null)
|
||||
drawObject(str, packet, 0);
|
||||
}
|
||||
|
||||
private int drawObject(StringBuilder str, Object o, int line, int indentation) {
|
||||
Field [] fields = o.getClass().getDeclaredFields();
|
||||
String formatString = (indentation>0)?("%-"+indentation*4+"s%-25s %s"):"%s%-25s %s";
|
||||
try {
|
||||
for (Field f : fields) {
|
||||
try {
|
||||
if (o instanceof Baseline && f.getType().equals(byte[].class)) {
|
||||
drawString(str, String.format(formatString, "", f.getName(), f.getType().getSimpleName()), line++);
|
||||
line = drawBaseline(str, (Baseline) o, line, indentation+1);
|
||||
} else
|
||||
line = drawObject(str, o, f, line, indentation);
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
private List<Field> getAllFields(List<Field> fields, Class<?> type) {
|
||||
Class<?> s = type.getSuperclass();
|
||||
if (s != null && (SWGPacket.class.isAssignableFrom(s) || BaselineObject.class.isAssignableFrom(s))) {
|
||||
fields = getAllFields(fields, type.getSuperclass());
|
||||
}
|
||||
return line;
|
||||
fields.addAll(Arrays.asList(type.getDeclaredFields()));
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
private int drawObject(StringBuilder str, Object o, Field f, int line, int indentation) throws IllegalArgumentException, IllegalAccessException {
|
||||
private void drawObject(StringBuilder str, Object o, int indentation) {
|
||||
for (Field f : getAllFields(new ArrayList<>(), o.getClass())) {
|
||||
if ((f.getModifiers() & (Modifier.STATIC | Modifier.TRANSIENT)) != 0)
|
||||
continue;
|
||||
drawObject(str, o, f, indentation);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawObject(StringBuilder str, Object o, Field f, int indentation) {
|
||||
f.setAccessible(true);
|
||||
String formatString = (indentation>0)?("%-"+indentation*4+"s%-25s %s"):"%s%-25s %s";
|
||||
Object field = f.get(o);
|
||||
if (field == null)
|
||||
drawString(str, String.format((indentation>0)?("%-"+indentation*4+"s%-25s null"):"%s%-25s null", "", f.getName()), line++);
|
||||
else if (field.getClass().isArray())
|
||||
line = drawArray(str, f, field, line, indentation);
|
||||
else if (field instanceof Collection)
|
||||
drawArray(str, f, ((Collection<?>)field).toArray(), line++, indentation);
|
||||
else if (field instanceof Enum<?> || field instanceof Enumeration<?>)
|
||||
drawString(str, String.format(formatString, "", f.getName(), field), line++);
|
||||
else if (field instanceof String || field instanceof Number || field instanceof Boolean)
|
||||
drawString(str, String.format(formatString, "", f.getName(), field), line++);
|
||||
else if (o instanceof Baseline && field instanceof byte[]) {
|
||||
drawString(str, String.format(formatString, "", f.getName(), field.getClass().getSimpleName()), line++);
|
||||
line = drawBaseline(str, (Baseline) o, line, indentation+1);
|
||||
} else {
|
||||
drawString(str, String.format(formatString, "", f.getName(), field.getClass().getSimpleName()), line++);
|
||||
line = drawObject(str, field, line, indentation+1);
|
||||
String format = (indentation>0)?("%-"+indentation*4+"s%-25s %s"):"%s%-25s %s";
|
||||
Object field;
|
||||
try {
|
||||
field = f.get(o);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
return line;
|
||||
boolean success = false;
|
||||
success = success || drawNull(str, f, field, format);
|
||||
success = success || drawNumber(str, f, field, format);
|
||||
success = success || drawEnum(str, f, field, format);
|
||||
success = success || drawCollection(str, f, field, format);
|
||||
if (!success)
|
||||
drawLeftover(str, f, field, o, format, indentation);
|
||||
}
|
||||
|
||||
private int drawArray(StringBuilder str, Field f, Object field, int line, int indentation) {
|
||||
String formatString = (indentation>0)?("%-"+indentation*4+"s%-25s %s"):"%s%-25s %s";
|
||||
private boolean drawNull(StringBuilder str, Field f, Object field, String format) {
|
||||
if (field == null) {
|
||||
drawString(str, String.format(format, "", f.getName(), "null"));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean drawNumber(StringBuilder str, Field f, Object field, String format) {
|
||||
if (field instanceof Integer) {
|
||||
if (f.getName().toLowerCase(Locale.US).contains("crc")) {
|
||||
drawString(str, String.format(format+" [%s]", "", f.getName(), field, crcDatabase.getString((Integer) field)));
|
||||
} else
|
||||
drawString(str, String.format(format, "", f.getName(), field));
|
||||
} else if (field instanceof String || field instanceof Number || field instanceof Boolean)
|
||||
drawString(str, String.format(format, "", f.getName(), field));
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean drawEnum(StringBuilder str, Field f, Object field, String format) {
|
||||
if (field instanceof Enum<?> || field instanceof Enumeration<?>)
|
||||
drawString(str, String.format(format, "", f.getName(), field));
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean drawCollection(StringBuilder str, Field f, Object field, String format) {
|
||||
if (field instanceof Collection)
|
||||
return drawArray(str, f, ((Collection<?>) field).toArray(), format);
|
||||
else if (field instanceof Map)
|
||||
drawString(str, String.format(format, "", f.getName(), field.getClass().getSimpleName() + " " + field));
|
||||
else if (field.getClass().isArray())
|
||||
drawArray(str, f, field, format);
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void drawLeftover(StringBuilder str, Field f, Object field, Object o, String format, int indent) {
|
||||
drawString(str, String.format(format, "", f.getName(), field.getClass().getSimpleName()));
|
||||
if (o instanceof Baseline && field instanceof byte[])
|
||||
drawBaseline(str, (Baseline) o, indent+1);
|
||||
else if (!field.getClass().isAssignableFrom(Object.class))
|
||||
drawObject(str, field, indent+1);
|
||||
}
|
||||
|
||||
private boolean drawArray(StringBuilder str, Field f, Object field, String format) {
|
||||
String array = drawArray(field);
|
||||
if (array != null)
|
||||
drawString(str, String.format(formatString, "", f.getName(), array), line++);
|
||||
drawString(str, String.format(format, "", f.getName(), f.getType().getSimpleName() + " " + array));
|
||||
else if (field != null) {
|
||||
drawString(str, String.format(formatString, "", f.getName(), "["), line++);
|
||||
drawString(str, String.format(format, "", f.getName(), f.getType().getName() + " ["));
|
||||
for (Object sub : (Object []) field) {
|
||||
drawString(str, String.format("%-"+(indentation+1)*4+"s%-25s %s", "", "", sub), line++);
|
||||
String subStr = drawArray(sub);
|
||||
if (subStr != null)
|
||||
drawString(str, String.format(" "+format, "", "", subStr));
|
||||
else
|
||||
drawString(str, String.format(" "+format, "", "", sub));
|
||||
}
|
||||
drawString(str, String.format(formatString, "", "", "]"), line++);
|
||||
}
|
||||
return line;
|
||||
drawString(str, String.format(format, "", "", "]"));
|
||||
} else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private String drawArray(Object o) {
|
||||
@@ -175,25 +244,25 @@ public class AnalysisPanel extends Pane implements Initializable, PacketSelected
|
||||
return null;
|
||||
}
|
||||
|
||||
private int drawBaseline(StringBuilder str, Baseline b, int line, int indentation) {
|
||||
private void drawBaseline(StringBuilder str, Baseline b, int indentation) {
|
||||
String formatString = (indentation>0)?("%-"+indentation*4+"s%-25s %s"):"%s%-20s %s";
|
||||
ByteBuffer data = ByteBuffer.wrap(b.getBaselineData());
|
||||
data.getShort();
|
||||
Map <String, Object> variables = new BaselineProcessor().process(data, b.getType(), b.getNum());
|
||||
for (Entry<String, Object> e : variables.entrySet()) {
|
||||
drawString(str, String.format(formatString, "", e.getKey(), e.getValue()), line++);
|
||||
drawString(str, String.format(formatString, "", e.getKey(), e.getValue()));
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
private void drawSOEPacket(StringBuilder str) {
|
||||
ByteBuffer data = packet.getData();
|
||||
data.position(0);
|
||||
int line = 0;
|
||||
drawString(str, "Date: " + dateFormat.format(this.packet.getTime()), line++);
|
||||
drawString(str, "Port: " + packet.getPort(), line++);
|
||||
drawString(str, "SOE Opcode: " + packet.getSOEOpcode(), line++);
|
||||
line = drawStrings(str, new JBuffer(data).toHexdump(), line);
|
||||
drawString(str, "Date: " + dateFormat.format(this.packet.getTime()));
|
||||
drawString(str, "Port: " + this.packet.getPacket().getAddress() + ":" + this.packet.getPort());
|
||||
drawString(str, "SOE Opcode: " + packet.getSOEOpcode());
|
||||
drawStrings(str, new JBuffer(data).toHexdump());
|
||||
drawString(str, "");
|
||||
drawObject(str, packet.getPacket(), 0);
|
||||
}
|
||||
|
||||
private String createRaw(ByteBuffer data) {
|
||||
@@ -202,7 +271,7 @@ public class AnalysisPanel extends Pane implements Initializable, PacketSelected
|
||||
StringBuilder ascii = new StringBuilder("");
|
||||
int ind = 0;
|
||||
int pos = 0;
|
||||
while (data.remaining() > 0) {
|
||||
while (data.hasRemaining()) {
|
||||
if (pos > 0 && pos % 4 == 0)
|
||||
s.append(' ');
|
||||
if (pos == 16) {
|
||||
@@ -241,7 +310,7 @@ public class AnalysisPanel extends Pane implements Initializable, PacketSelected
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
private int drawStrings(StringBuilder str, String completeStr, int line) {
|
||||
private void drawStrings(StringBuilder str, String completeStr) {
|
||||
String [] strLines = completeStr.split("\n");
|
||||
for (String s : strLines) {
|
||||
int finalIndex = 0;
|
||||
@@ -255,12 +324,11 @@ public class AnalysisPanel extends Pane implements Initializable, PacketSelected
|
||||
finalIndex = i+5;
|
||||
}
|
||||
s = s.substring(0, finalIndex).toUpperCase() + s.substring(finalIndex);
|
||||
drawString(str, s, line++);
|
||||
drawString(str, s);
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
private void drawString(StringBuilder s, String str, int line) {
|
||||
private void drawString(StringBuilder s, String str) {
|
||||
s.append(str + '\n');
|
||||
}
|
||||
|
||||
|
||||
@@ -3,83 +3,157 @@ package com.projectswg.layout;
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import com.projectswg.PacketSelectedCallback;
|
||||
import resources.objects.SWGObject;
|
||||
|
||||
import com.projectswg.ItemSelectedCallback;
|
||||
import com.projectswg.LeftPanelContent;
|
||||
import com.projectswg.PacketMasterData;
|
||||
import com.projectswg.gui.GUIPacket;
|
||||
import com.projectswg.packets.PacketData;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.SelectionMode;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.Background;
|
||||
import javafx.scene.layout.BackgroundFill;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
public class PacketPanel extends Pane implements Initializable, PacketSelectedCallback {
|
||||
public class PacketPanel extends Pane implements Initializable, ItemSelectedCallback {
|
||||
|
||||
private final PacketMasterData packetMasterData;
|
||||
private final PacketData packetData;
|
||||
|
||||
private ListView<GUIPacket> list;
|
||||
private ObservableList<GUIPacket> items;
|
||||
private PacketSelectedCallback selectedCallback;
|
||||
private ListView<GUIPacket> packetList;
|
||||
private ListView<SWGObject> objectList;
|
||||
private ObservableList<GUIPacket> packetItems;
|
||||
private ObservableList<SWGObject> objectItems;
|
||||
private ItemSelectedCallback selectedCallback;
|
||||
private TabPane tabPane;
|
||||
private Tab packetTab;
|
||||
private Tab objectTab;
|
||||
|
||||
public PacketPanel(PacketData packetData) {
|
||||
this.packetData = packetData;
|
||||
public PacketPanel(PacketMasterData packetData) {
|
||||
this.packetMasterData = packetData;
|
||||
this.packetData = packetData.getData();
|
||||
LayoutLoader.load("PacketPanel.fxml", this, this);
|
||||
selectedCallback = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
list = new ListView<>();
|
||||
list.setEditable(false);
|
||||
list.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
|
||||
list.setCellFactory((param) -> new PacketListCell());
|
||||
list.setOnMouseClicked((event) -> {
|
||||
packetList = new ListView<>();
|
||||
packetList.setEditable(false);
|
||||
packetList.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
|
||||
packetList.setCellFactory((param) -> new PacketListCell());
|
||||
packetList.setOnMouseClicked((event) -> {
|
||||
if (selectedCallback != null) {
|
||||
int index = list.getSelectionModel().getSelectedIndex();
|
||||
packetData.setSelectedIndex(index);
|
||||
selectedCallback.onPacketSelected(index);
|
||||
int index = packetList.getSelectionModel().getSelectedIndex();
|
||||
if (index >= 0 && index < packetData.size()) {
|
||||
packetData.setSelectedIndex(index);
|
||||
selectedCallback.onPacketSelected(index);
|
||||
}
|
||||
}
|
||||
});
|
||||
objectList = new ListView<>();
|
||||
objectList.setEditable(false);
|
||||
objectList.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
|
||||
objectList.setCellFactory((param) -> new ObjectListCell());
|
||||
objectList.setOnMouseClicked((event) -> {
|
||||
if (selectedCallback != null) {
|
||||
SWGObject obj = objectList.getSelectionModel().getSelectedItem();
|
||||
if (obj == null)
|
||||
return;
|
||||
long id = obj.getObjectId();
|
||||
packetData.setSelectedId(id);
|
||||
selectedCallback.onObjectSelected(id);
|
||||
}
|
||||
});
|
||||
updatePackets();
|
||||
getChildren().add(list);
|
||||
updateObjects();
|
||||
tabPane = new TabPane();
|
||||
packetTab = new Tab("Packets", packetList);
|
||||
objectTab = new Tab("Objects", objectList);
|
||||
tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {
|
||||
@Override
|
||||
public void changed(ObservableValue<? extends Tab> ov, Tab oldTab, Tab newTab) {
|
||||
if (newTab == packetTab)
|
||||
packetMasterData.setLeftPanelContent(LeftPanelContent.PACKETS);
|
||||
else if (newTab == objectTab)
|
||||
packetMasterData.setLeftPanelContent(LeftPanelContent.OBJECTS);
|
||||
}
|
||||
});
|
||||
packetTab.setClosable(false);
|
||||
objectTab.setClosable(false);
|
||||
packetTab.setTooltip(new Tooltip("Raw Packet List"));
|
||||
objectTab.setTooltip(new Tooltip("Object List"));
|
||||
tabPane.getTabs().add(packetTab);
|
||||
tabPane.getTabs().add(objectTab);
|
||||
getChildren().add(tabPane);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSelected(int index) {
|
||||
tabPane.getSelectionModel().select(packetTab);
|
||||
packetData.setSelectedIndex(index);
|
||||
list.getSelectionModel().clearAndSelect(index);
|
||||
list.getFocusModel().focus(index);
|
||||
list.scrollTo(index);
|
||||
packetList.getSelectionModel().clearAndSelect(index);
|
||||
packetList.getFocusModel().focus(index);
|
||||
packetList.scrollTo(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onObjectSelected(long objectId) {
|
||||
tabPane.getSelectionModel().select(objectTab);
|
||||
packetData.setSelectedId(objectId);
|
||||
SWGObject obj = packetData.getObject(objectId);
|
||||
if (obj == null) {
|
||||
System.err.println("Object not found for ID: " + objectId);
|
||||
return;
|
||||
}
|
||||
int index = objectItems.indexOf(obj);
|
||||
if (index == -1) {
|
||||
System.err.println("Item index not found!");
|
||||
return;
|
||||
}
|
||||
packetData.setSelectedIndex(index);
|
||||
objectList.getSelectionModel().clearAndSelect(index);
|
||||
objectList.getFocusModel().focus(index);
|
||||
objectList.scrollTo(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void layoutChildren() {
|
||||
super.layoutChildren();
|
||||
list.resize(getWidth(), getHeight());
|
||||
tabPane.resize(getWidth(), getHeight());
|
||||
}
|
||||
|
||||
public void setPacketSelectedCallback(PacketSelectedCallback callback) {
|
||||
public void setPacketSelectedCallback(ItemSelectedCallback callback) {
|
||||
this.selectedCallback = callback;
|
||||
}
|
||||
|
||||
public void updatePackets() {
|
||||
items = FXCollections.observableArrayList();
|
||||
for (GUIPacket packet : packetData.getPackets()) {
|
||||
items.add(packet);
|
||||
}
|
||||
Platform.runLater(() -> list.setItems(items));
|
||||
packetItems = FXCollections.observableArrayList(packetData.getPackets());
|
||||
Platform.runLater(() -> packetList.setItems(packetItems));
|
||||
}
|
||||
|
||||
public void updateObjects() {
|
||||
objectItems = FXCollections.observableArrayList(packetData.getObjects());
|
||||
Platform.runLater(() -> objectList.setItems(objectItems));
|
||||
}
|
||||
|
||||
private static class PacketListCell extends ListCell<GUIPacket> {
|
||||
|
||||
private static final Background SOE_PACKET = new Background(new BackgroundFill(new Color(0, .75, 0, 1), null, null));
|
||||
private static final Background SWG_PACKET = new Background(new BackgroundFill(new Color(.6, .6, .6, 1), null, null));
|
||||
private static final Background SOE_PACKET = new Background(new BackgroundFill(new Color(.6, .6, .6, 1), null, null));
|
||||
private static final Background SWG_PACKET = new Background(new BackgroundFill(new Color(0, .75, 0, 1), null, null));
|
||||
|
||||
@Override
|
||||
public void updateItem(GUIPacket packet, boolean empty) {
|
||||
@@ -98,4 +172,23 @@ public class PacketPanel extends Pane implements Initializable, PacketSelectedCa
|
||||
}
|
||||
}
|
||||
|
||||
private static class ObjectListCell extends ListCell<SWGObject> {
|
||||
|
||||
private static final Background BACKGROUND = new Background(new BackgroundFill(new Color(.8, .8, .8, 1), null, null));
|
||||
|
||||
@Override
|
||||
public void updateItem(SWGObject object, boolean empty) {
|
||||
super.updateItem(object, empty);
|
||||
if (empty) {
|
||||
setText(null);
|
||||
setGraphic(null);
|
||||
setBackground(BACKGROUND);
|
||||
} else {
|
||||
setText(object.getClass().getSimpleName());
|
||||
setGraphic(null);
|
||||
setBackground(BACKGROUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
|
||||
<fx:root type="com.projectswg.layout.ToolbarPanel" id="toolbarPanel" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<TextField fx:id="searchText" translateX="5" prefWidth="200" promptText="Search" onAction="#search" />
|
||||
<TextField fx:id="searchText" translateX="5" prefWidth="195" promptText="Search" onAction="#search" />
|
||||
<Button fx:id="prevButton" text="Prev" translateX="10" onAction="#searchPrev" />
|
||||
<Button fx:id="nextButton" text="Next" translateX="15" onAction="#searchNext" />
|
||||
<CheckBox fx:id="searchSOE" text="Search SOE" translateX="20" selected="true" />
|
||||
<CheckBox fx:id="searchSOE" text="Search SOE" translateX="20" selected="false" />
|
||||
<CheckBox fx:id="searchSWG" text="Search SWG" translateX="25" selected="true" />
|
||||
</fx:root>
|
||||
|
||||
|
||||
@@ -5,9 +5,13 @@ import java.util.HashSet;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
|
||||
import com.projectswg.PacketSelectedCallback;
|
||||
import com.projectswg.packets.PacketData;
|
||||
import resources.objects.SWGObject;
|
||||
|
||||
import com.projectswg.ItemSelectedCallback;
|
||||
import com.projectswg.PacketMasterData;
|
||||
import com.projectswg.packets.ObjectSearcher;
|
||||
import com.projectswg.packets.PacketSearcher;
|
||||
import com.projectswg.packets.Searcher;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
@@ -20,9 +24,9 @@ import javafx.scene.layout.HBox;
|
||||
|
||||
public class ToolbarPanel extends HBox implements Initializable {
|
||||
|
||||
private final PacketData packetData;
|
||||
private final PacketMasterData packetData;
|
||||
|
||||
private Set<PacketSelectedCallback> callbacks;
|
||||
private Set<ItemSelectedCallback> callbacks;
|
||||
|
||||
@FXML private TextField searchText;
|
||||
@FXML private Button prevButton;
|
||||
@@ -30,7 +34,7 @@ public class ToolbarPanel extends HBox implements Initializable {
|
||||
@FXML private CheckBox searchSOE;
|
||||
@FXML private CheckBox searchSWG;
|
||||
|
||||
public ToolbarPanel(PacketData data) {
|
||||
public ToolbarPanel(PacketMasterData data) {
|
||||
this.packetData = data;
|
||||
callbacks = new HashSet<>();
|
||||
LayoutLoader.load("ToolbarPanel.fxml", this, this);
|
||||
@@ -41,7 +45,7 @@ public class ToolbarPanel extends HBox implements Initializable {
|
||||
setAlignment(Pos.CENTER_LEFT);
|
||||
}
|
||||
|
||||
public void addPacketSelectedCallback(PacketSelectedCallback callback) {
|
||||
public void addPacketSelectedCallback(ItemSelectedCallback callback) {
|
||||
this.callbacks.add(callback);
|
||||
}
|
||||
|
||||
@@ -53,11 +57,22 @@ public class ToolbarPanel extends HBox implements Initializable {
|
||||
@FXML
|
||||
private void searchPrev(ActionEvent event) {
|
||||
System.out.println("Search Prev: " + searchText.getText());
|
||||
PacketSearcher searcher = new PacketSearcher(packetData, searchSOE.isSelected(), searchSWG.isSelected());
|
||||
int index = searcher.searchBackward(packetData.getSelectedIndex(), searchText.getText(), true);
|
||||
Searcher searcher;
|
||||
switch (packetData.getLeftPanelContent()) {
|
||||
case PACKETS: searcher = new PacketSearcher(packetData); break;
|
||||
case OBJECTS: searcher = new ObjectSearcher(packetData); break;
|
||||
default: searcher = null; break;
|
||||
}
|
||||
int index = searcher.searchBackward(packetData.getData().getSelectedIndex(), searchText.getText(), true);
|
||||
if (index != -1) {
|
||||
for (PacketSelectedCallback callback : callbacks)
|
||||
callback.onPacketSelected(index);
|
||||
if (searcher instanceof PacketSearcher) {
|
||||
for (ItemSelectedCallback callback : callbacks)
|
||||
callback.onPacketSelected(index);
|
||||
} else if (searcher instanceof ObjectSearcher) {
|
||||
SWGObject selected = ((ObjectSearcher) searcher).getLastMatch();
|
||||
for (ItemSelectedCallback callback : callbacks)
|
||||
callback.onObjectSelected(selected.getObjectId());
|
||||
}
|
||||
} else {
|
||||
System.err.println("No packet found for search: " + searchText.getText());
|
||||
}
|
||||
@@ -66,11 +81,26 @@ public class ToolbarPanel extends HBox implements Initializable {
|
||||
@FXML
|
||||
private void searchNext(ActionEvent event) {
|
||||
System.out.println("Search Next: " + searchText.getText());
|
||||
PacketSearcher searcher = new PacketSearcher(packetData, searchSOE.isSelected(), searchSWG.isSelected());
|
||||
int index = searcher.searchForward(packetData.getSelectedIndex()+1, searchText.getText(), true);
|
||||
Searcher searcher;
|
||||
switch (packetData.getLeftPanelContent()) {
|
||||
case PACKETS: searcher = new PacketSearcher(packetData); break;
|
||||
case OBJECTS: searcher = new ObjectSearcher(packetData); break;
|
||||
default: searcher = null; break;
|
||||
}
|
||||
int index = searcher.searchForward(packetData.getData().getSelectedIndex()+1, searchText.getText(), true);
|
||||
if (index != -1) {
|
||||
for (PacketSelectedCallback callback : callbacks)
|
||||
callback.onPacketSelected(index);
|
||||
switch (packetData.getLeftPanelContent()) {
|
||||
case PACKETS:
|
||||
for (ItemSelectedCallback callback : callbacks)
|
||||
callback.onPacketSelected(index);
|
||||
break;
|
||||
case OBJECTS: {
|
||||
SWGObject selected = packetData.getData().getObjects().get(index);
|
||||
for (ItemSelectedCallback callback : callbacks)
|
||||
callback.onObjectSelected(selected.getObjectId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.err.println("No packet found for search: " + searchText.getText());
|
||||
}
|
||||
|
||||
268
src/com/projectswg/network/packets/Packet.java
Normal file
268
src/com/projectswg/network/packets/Packet.java
Normal file
@@ -0,0 +1,268 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.network.packets;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class Packet extends network.packets.Packet {
|
||||
public static final Charset ascii = Charset.forName("UTF-8");
|
||||
public static final Charset unicode = Charset.forName("UTF-16LE");
|
||||
private InetAddress address;
|
||||
private ByteBuffer data;
|
||||
private Date time;
|
||||
private int port = 0;
|
||||
private int opcode;
|
||||
|
||||
public Packet() {
|
||||
data = ByteBuffer.allocate(2);
|
||||
}
|
||||
|
||||
public Packet(ByteBuffer data) {
|
||||
decode(data);
|
||||
}
|
||||
|
||||
public void setAddress(InetAddress address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public InetAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public Date getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(Date time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public void setOpcode(int opcode) {
|
||||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
public int getOpcode() {
|
||||
return opcode;
|
||||
}
|
||||
|
||||
public static void addList(ByteBuffer bb, List<byte[]> list) {
|
||||
addInt(bb, list.size());
|
||||
for (byte[] bytes : list) {
|
||||
addData(bb, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addBoolean(ByteBuffer bb, boolean b) {
|
||||
bb.put(b ? (byte) 1 : (byte) 0);
|
||||
}
|
||||
|
||||
public static void addAscii(ByteBuffer bb, String s) {
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
bb.putShort((short) s.length());
|
||||
bb.put(s.getBytes(ascii));
|
||||
}
|
||||
|
||||
public static void addUnicode(ByteBuffer bb, String s) {
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
bb.putInt(s.length());
|
||||
bb.put(s.getBytes(unicode));
|
||||
}
|
||||
|
||||
public static void addLong(ByteBuffer bb, long l) {
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN).putLong(l);
|
||||
}
|
||||
|
||||
public static void addInt(ByteBuffer bb, int i) {
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN).putInt(i);
|
||||
}
|
||||
|
||||
public static void addFloat(ByteBuffer bb, float f) {
|
||||
bb.putFloat(f);
|
||||
}
|
||||
|
||||
public static void addShort(ByteBuffer bb, int i) {
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN).putShort((short) i);
|
||||
}
|
||||
|
||||
public static void addNetLong(ByteBuffer bb, long l) {
|
||||
bb.order(ByteOrder.BIG_ENDIAN).putLong(l);
|
||||
}
|
||||
|
||||
public static void addNetInt(ByteBuffer bb, int i) {
|
||||
bb.order(ByteOrder.BIG_ENDIAN).putInt(i);
|
||||
}
|
||||
|
||||
public static void addNetShort(ByteBuffer bb, int i) {
|
||||
bb.order(ByteOrder.BIG_ENDIAN).putShort((short) i);
|
||||
}
|
||||
|
||||
public static void addByte(ByteBuffer bb, int b) {
|
||||
bb.put((byte) b);
|
||||
}
|
||||
|
||||
public static void addData(ByteBuffer bb, byte[] data) {
|
||||
bb.put(data);
|
||||
}
|
||||
|
||||
public static void addArray(ByteBuffer bb, byte[] data) {
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
addShort(bb, data.length);
|
||||
addData(bb, data);
|
||||
}
|
||||
|
||||
public static void addArrayList(ByteBuffer bb, byte[] b) {
|
||||
addShort(bb, b.length);
|
||||
bb.put(b);
|
||||
}
|
||||
|
||||
public static boolean getBoolean(ByteBuffer bb) {
|
||||
return getByte(bb) == 1;
|
||||
}
|
||||
|
||||
public static String getAscii(ByteBuffer bb) {
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
short length = bb.getShort();
|
||||
if (length > bb.remaining())
|
||||
return "";
|
||||
byte [] str = new byte[length];
|
||||
bb.get(str);
|
||||
return new String(str, ascii);
|
||||
}
|
||||
|
||||
public static String getUnicode(ByteBuffer bb) {
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
int length = bb.getInt() * 2;
|
||||
if (length > bb.remaining())
|
||||
return "";
|
||||
byte [] str = new byte[length];
|
||||
bb.get(str);
|
||||
return new String(str, unicode);
|
||||
}
|
||||
|
||||
public static byte getByte(ByteBuffer bb) {
|
||||
return bb.get();
|
||||
}
|
||||
|
||||
public static short getShort(ByteBuffer bb) {
|
||||
return bb.order(ByteOrder.LITTLE_ENDIAN).getShort();
|
||||
}
|
||||
|
||||
public static int getInt(ByteBuffer bb) {
|
||||
return bb.order(ByteOrder.LITTLE_ENDIAN).getInt();
|
||||
}
|
||||
|
||||
public static float getFloat(ByteBuffer bb) {
|
||||
return bb.getFloat();
|
||||
}
|
||||
|
||||
public static long getLong(ByteBuffer bb) {
|
||||
return bb.order(ByteOrder.LITTLE_ENDIAN).getLong();
|
||||
}
|
||||
|
||||
public static short getNetShort(ByteBuffer bb) {
|
||||
return bb.order(ByteOrder.BIG_ENDIAN).getShort();
|
||||
}
|
||||
|
||||
public static int getNetInt(ByteBuffer bb) {
|
||||
return bb.order(ByteOrder.BIG_ENDIAN).getInt();
|
||||
}
|
||||
|
||||
public static long getNetLong(ByteBuffer bb) {
|
||||
return bb.order(ByteOrder.BIG_ENDIAN).getLong();
|
||||
}
|
||||
|
||||
public static byte [] getArray(ByteBuffer bb) {
|
||||
byte [] data = new byte[getShort(bb)];
|
||||
bb.get(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public static byte [] getArray(ByteBuffer bb, int length) {
|
||||
byte [] data = new byte[length];
|
||||
bb.get(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public static int [] getIntArray(ByteBuffer bb) {
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
int [] ints = new int[bb.getInt()];
|
||||
for (int i = 0; i < ints.length; i++)
|
||||
ints[i] = bb.getInt();
|
||||
return ints;
|
||||
}
|
||||
|
||||
public static int [] getIntArray(ByteBuffer bb, int size) {
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
int [] ints = new int[size];
|
||||
for (int i = 0; i < ints.length; i++)
|
||||
ints[i] = bb.getInt();
|
||||
return ints;
|
||||
}
|
||||
|
||||
public static boolean[] getBooleanArray(ByteBuffer bb) {
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
boolean[] booleans = new boolean[bb.getInt()];
|
||||
for(int i = 0; i < booleans.length; i++)
|
||||
booleans[i] = getBoolean(bb);
|
||||
return booleans;
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer data) {
|
||||
data.position(0);
|
||||
this.data = data;
|
||||
opcode = getNetShort(data);
|
||||
data.position(0);
|
||||
}
|
||||
|
||||
public ByteBuffer getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public ByteBuffer encode() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
67
src/com/projectswg/network/packets/soe/Acknowledge.java
Normal file
67
src/com/projectswg/network/packets/soe/Acknowledge.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.network.packets.soe;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.projectswg.network.packets.Packet;
|
||||
|
||||
public class Acknowledge extends Packet {
|
||||
|
||||
private short sequence;
|
||||
|
||||
public Acknowledge() {
|
||||
sequence = 0;
|
||||
}
|
||||
|
||||
public Acknowledge(ByteBuffer data) {
|
||||
decode(data);
|
||||
}
|
||||
|
||||
public Acknowledge(short sequence) {
|
||||
this.sequence = sequence;
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer data) {
|
||||
super.decode(data);
|
||||
data.position(2);
|
||||
sequence = getNetShort(data);
|
||||
}
|
||||
|
||||
public ByteBuffer encode() {
|
||||
ByteBuffer data = ByteBuffer.allocate(4);
|
||||
addNetShort(data, 21);
|
||||
addNetShort(data, sequence);
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setSequence(short sequence) { this.sequence = sequence; }
|
||||
|
||||
public short getSequence() { return sequence; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.network.packets.soe;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.projectswg.network.packets.Packet;
|
||||
|
||||
|
||||
public class ClientNetworkStatusUpdate extends Packet {
|
||||
|
||||
private int clientTickCount;
|
||||
private int lastUpdate;
|
||||
private int avgUpdate;
|
||||
private int shortUpdate;
|
||||
private int longUpdate;
|
||||
private int lastServerUpdate;
|
||||
private long packetSent;
|
||||
private long packetRecv;
|
||||
|
||||
public ClientNetworkStatusUpdate() {
|
||||
|
||||
}
|
||||
|
||||
public ClientNetworkStatusUpdate(ByteBuffer data) {
|
||||
decode(data);
|
||||
}
|
||||
|
||||
public ClientNetworkStatusUpdate(int clientTickCount, int lastUpdate, int avgUpdate, int shortUpdate, int longUpdate, int lastServerUpdate, long packetsSent, long packetsRecv) {
|
||||
this.clientTickCount = clientTickCount;
|
||||
this.lastUpdate = lastUpdate;
|
||||
this.avgUpdate = avgUpdate;
|
||||
this.shortUpdate = shortUpdate;
|
||||
this.longUpdate = longUpdate;
|
||||
this.lastServerUpdate = lastServerUpdate;
|
||||
this.packetSent = packetsSent;
|
||||
this.packetRecv = packetsRecv;
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer data) {
|
||||
super.decode(data);
|
||||
data.position(2);
|
||||
clientTickCount = getNetShort(data);
|
||||
lastUpdate = getNetInt(data);
|
||||
avgUpdate = getNetInt(data);
|
||||
shortUpdate = getNetInt(data);
|
||||
longUpdate = getNetInt(data);
|
||||
lastServerUpdate = getNetInt(data);
|
||||
packetSent = getNetLong(data);
|
||||
packetRecv = getNetLong(data);
|
||||
}
|
||||
|
||||
public ByteBuffer encode() {
|
||||
ByteBuffer data = ByteBuffer.allocate(40);
|
||||
addNetShort(data, 7);
|
||||
addNetShort(data, clientTickCount);
|
||||
addNetInt( data, lastUpdate);
|
||||
addNetInt( data, avgUpdate);
|
||||
addNetInt( data, shortUpdate);
|
||||
addNetInt( data, longUpdate);
|
||||
addNetInt( data, lastServerUpdate);
|
||||
addNetLong( data, packetSent);
|
||||
addNetLong( data, packetRecv);
|
||||
return data;
|
||||
}
|
||||
|
||||
public int getTick() { return clientTickCount; }
|
||||
public int getLastUpdate() { return lastUpdate; }
|
||||
public int getAverageUpdate() { return avgUpdate; }
|
||||
public int getShortestUpdate() { return shortUpdate; }
|
||||
public int getLongestUpdate() { return longUpdate; }
|
||||
public int getLastServerUpdate() { return lastServerUpdate; }
|
||||
public long getSent() { return packetSent; }
|
||||
public long getRecv() { return packetRecv; }
|
||||
|
||||
public void setTick(int tick) { this.clientTickCount = tick; }
|
||||
public void setLastUpdate(int last) { this.lastUpdate = last; }
|
||||
public void setAverageUpdate(int avg) { this.avgUpdate = avg; }
|
||||
public void setShortestUpdate(int shortest) { this.shortUpdate = shortest; }
|
||||
public void setLongestUpdate(int longest) { this.longUpdate = longest; }
|
||||
public void setLastServerUpdate(int last) { this.lastServerUpdate = last; }
|
||||
public void setPacketsSent(long sent) { this.packetSent = sent; }
|
||||
public void setPacketsRecv(long recv) { this.packetRecv = recv; }
|
||||
}
|
||||
165
src/com/projectswg/network/packets/soe/DataChannel.java
Normal file
165
src/com/projectswg/network/packets/soe/DataChannel.java
Normal file
@@ -0,0 +1,165 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.network.packets.soe;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.projectswg.network.packets.Packet;
|
||||
|
||||
|
||||
public class DataChannel extends Packet implements SequencedPacket {
|
||||
|
||||
private List <byte []> content = new ArrayList<byte []>();
|
||||
private short sequence = 0;
|
||||
private short multiPacket = 0;
|
||||
|
||||
public DataChannel() {
|
||||
|
||||
}
|
||||
|
||||
public DataChannel(ByteBuffer data) {
|
||||
decode(data);
|
||||
}
|
||||
|
||||
public DataChannel(byte [][] packets) {
|
||||
for (byte [] p : packets) {
|
||||
content.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer data) {
|
||||
super.decode(data);
|
||||
if (getOpcode() != 9) {
|
||||
throw new IllegalArgumentException("Buffer does not contain DataChannelA!");
|
||||
}
|
||||
data.position(2);
|
||||
sequence = getNetShort(data);
|
||||
multiPacket = getNetShort(data);
|
||||
if (multiPacket == 0x19) {
|
||||
int length = 0;
|
||||
while (data.remaining() > 1) {
|
||||
length = getByte(data) & 0xFF;
|
||||
if (length == 0xFF)
|
||||
length = getNetShort(data);
|
||||
if (length > data.remaining()) {
|
||||
data.position(data.position()-1);
|
||||
return;
|
||||
}
|
||||
byte [] pData = new byte[length];
|
||||
data.get(pData);
|
||||
content.add(pData);
|
||||
}
|
||||
} else {
|
||||
data.position(data.position()-2);
|
||||
byte [] pData = new byte[data.remaining()];
|
||||
data.get(pData);
|
||||
content.add(pData);
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBuffer encode() {
|
||||
return encode(this.sequence);
|
||||
}
|
||||
|
||||
public ByteBuffer encode(int sequence) {
|
||||
this.sequence = (short) sequence;
|
||||
if (content.size() == 1) {
|
||||
byte [] pData = content.get(0);
|
||||
ByteBuffer data = ByteBuffer.allocate(4 + pData.length);
|
||||
addNetShort(data, 9);
|
||||
addNetShort(data, sequence);
|
||||
data.put(pData);
|
||||
return data;
|
||||
} else if (content.size() > 1) {
|
||||
int length = getLength();
|
||||
ByteBuffer data= ByteBuffer.allocate(length);
|
||||
addNetShort(data, 9);
|
||||
addNetShort(data, sequence);
|
||||
addNetShort(data, 0x19);
|
||||
for (byte [] pData : content) {
|
||||
if (pData.length >= 0xFF) {
|
||||
addByte(data, 0xFF);
|
||||
addNetShort(data, pData.length);
|
||||
} else {
|
||||
data.put((byte) pData.length);
|
||||
}
|
||||
data.put(pData);
|
||||
}
|
||||
return data;
|
||||
} else {
|
||||
return ByteBuffer.allocate(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPacket(byte [] packet) {
|
||||
content.add(packet);
|
||||
}
|
||||
|
||||
public void clearPackets() {
|
||||
content.clear();
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
if (content.size() == 1) {
|
||||
return 4 + content.get(0).length;
|
||||
} else {
|
||||
int length = 6;
|
||||
for (byte [] packet : content) {
|
||||
int addLength = packet.length;
|
||||
length += 1 + addLength + ((addLength >= 0xFF) ? 2 : 0);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(SequencedPacket p) {
|
||||
return Short.compare(sequence, p.getSequence());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof DataChannel)
|
||||
return ((DataChannel) o).sequence == sequence;
|
||||
if (o instanceof SequencedPacket)
|
||||
return ((SequencedPacket) o).getSequence() == sequence;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
public void setSequence(short sequence) { this.sequence = sequence; }
|
||||
|
||||
public short getSequence() { return sequence; }
|
||||
public List <byte []> getPackets() { return content; }
|
||||
}
|
||||
105
src/com/projectswg/network/packets/soe/Disconnect.java
Normal file
105
src/com/projectswg/network/packets/soe/Disconnect.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.network.packets.soe;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.projectswg.network.packets.Packet;
|
||||
|
||||
|
||||
public class Disconnect extends Packet {
|
||||
|
||||
private int connectionId;
|
||||
private DisconnectReason reason;
|
||||
|
||||
public Disconnect() {
|
||||
connectionId = 0;
|
||||
reason = DisconnectReason.NONE;
|
||||
}
|
||||
|
||||
public Disconnect(int connectionId, DisconnectReason reason) {
|
||||
this.connectionId = connectionId;
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
public Disconnect(ByteBuffer data){
|
||||
this.decode(data);
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer data) {
|
||||
data.position(2);
|
||||
connectionId = getNetInt(data);
|
||||
reason = getReason(getNetShort(data));
|
||||
}
|
||||
|
||||
public ByteBuffer encode() {
|
||||
ByteBuffer data = ByteBuffer.allocate(8);
|
||||
addNetShort(data, 5);
|
||||
addNetInt(data, connectionId);
|
||||
addNetShort(data, reason.getReason());
|
||||
return data;
|
||||
}
|
||||
|
||||
public int getConnectionID() { return connectionId; }
|
||||
public DisconnectReason getReason() { return reason; }
|
||||
|
||||
private DisconnectReason getReason(int reason) {
|
||||
for (DisconnectReason dr : DisconnectReason.values())
|
||||
if (dr.getReason() == reason)
|
||||
return dr;
|
||||
return DisconnectReason.NONE;
|
||||
}
|
||||
|
||||
public enum DisconnectReason {
|
||||
NONE (0x00),
|
||||
ICMP_ERROR (0x01),
|
||||
TIMEOUT (0x02),
|
||||
OTHER_SIDE_TERMINATED (0x03),
|
||||
MANAGER_DELETED (0x04),
|
||||
CONNECT_FAIL (0x05),
|
||||
APPLICATION (0x06),
|
||||
UNREACHABLE_CONNECTION (0x07),
|
||||
UNACKNOWLEDGED_TIMEOUT (0x08),
|
||||
NEW_CONNECTION_ATTEMPT (0x09),
|
||||
CONNECTION_REFUSED (0x0A),
|
||||
MUTUAL_CONNETION_ERROR (0x0B),
|
||||
CONNETING_TO_SELF (0x0C),
|
||||
RELIABLE_OVERFLOW (0x0D),
|
||||
COUNT (0x0E);
|
||||
|
||||
private short reason;
|
||||
|
||||
DisconnectReason(int reason) {
|
||||
this.reason = (short) reason;
|
||||
}
|
||||
|
||||
public short getReason() {
|
||||
return reason;
|
||||
}
|
||||
}
|
||||
}
|
||||
138
src/com/projectswg/network/packets/soe/Fragmented.java
Normal file
138
src/com/projectswg/network/packets/soe/Fragmented.java
Normal file
@@ -0,0 +1,138 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.network.packets.soe;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.projectswg.network.packets.Packet;
|
||||
|
||||
|
||||
public class Fragmented extends Packet implements SequencedPacket {
|
||||
|
||||
private short sequence;
|
||||
private int length;
|
||||
private ByteBuffer packet;
|
||||
private ByteBuffer data;
|
||||
|
||||
public Fragmented() {
|
||||
this.sequence = 0;
|
||||
this.length = 0;
|
||||
this.packet = null;
|
||||
this.data = null;
|
||||
}
|
||||
|
||||
public Fragmented(ByteBuffer data) {
|
||||
decode(data);
|
||||
length = -1;
|
||||
}
|
||||
|
||||
public Fragmented(ByteBuffer data, int sequence) {
|
||||
this.sequence = (short) sequence;
|
||||
decode(data);
|
||||
length = -1;
|
||||
}
|
||||
|
||||
public void setPacket(ByteBuffer packet) {
|
||||
this.packet = packet;
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer data) {
|
||||
super.decode(data);
|
||||
data.position(2);
|
||||
sequence = getNetShort(data);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public ByteBuffer encode() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public Fragmented [] encode(int startSequence) {
|
||||
packet.position(0);
|
||||
int ord = 0;
|
||||
Fragmented [] packets = new Fragmented[(int) Math.ceil((packet.remaining()+4)/489.0)];
|
||||
while (packet.remaining() > 0) {
|
||||
packets[ord] = createSegment(startSequence++, ord++, packet);
|
||||
}
|
||||
return packets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(SequencedPacket p) {
|
||||
return Short.compare(sequence, p.getSequence());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof Fragmented)
|
||||
return ((Fragmented) o).sequence == sequence;
|
||||
if (o instanceof SequencedPacket)
|
||||
return ((SequencedPacket) o).getSequence() == sequence;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
public ByteBuffer getPacketData() { return data; }
|
||||
public short getSequence() { return sequence; }
|
||||
public int getDatLength() { return length; }
|
||||
|
||||
public static final Fragmented [] encode(ByteBuffer data, int startSequence) {
|
||||
data.position(0);
|
||||
int ord = 0;
|
||||
Fragmented [] packets = new Fragmented[(int) Math.ceil((data.remaining()+4)/489.0)];
|
||||
while (data.remaining() > 0) {
|
||||
packets[ord] = createSegment(startSequence++, ord++, data);
|
||||
}
|
||||
return packets;
|
||||
}
|
||||
|
||||
private static final Fragmented createSegment(int startSequence, int ord, ByteBuffer packet) {
|
||||
int header = (ord == 0) ? 8 : 4;
|
||||
ByteBuffer data = ByteBuffer.allocate(Math.min(packet.remaining()+header, 493));
|
||||
|
||||
addNetShort(data, 0x0D);
|
||||
addNetShort(data, startSequence);
|
||||
if (ord == 0)
|
||||
addNetInt(data, packet.remaining());
|
||||
|
||||
int len = data.remaining();
|
||||
data.put(packet.array(), packet.position(), len);
|
||||
packet.position(packet.position() + len);
|
||||
|
||||
byte [] pData = new byte[data.array().length-header];
|
||||
System.arraycopy(data.array(), header, pData, 0, pData.length);
|
||||
Fragmented f = new Fragmented(data, startSequence);
|
||||
f.packet = ByteBuffer.wrap(pData);
|
||||
return f;
|
||||
}
|
||||
|
||||
}
|
||||
27
src/com/projectswg/network/packets/soe/KeepAlive.java
Normal file
27
src/com/projectswg/network/packets/soe/KeepAlive.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package com.projectswg.network.packets.soe;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.projectswg.network.packets.Packet;
|
||||
|
||||
public class KeepAlive extends Packet {
|
||||
|
||||
public KeepAlive() {
|
||||
|
||||
}
|
||||
|
||||
public KeepAlive(ByteBuffer data) {
|
||||
decode(data);
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer data) {
|
||||
data.position(2);
|
||||
}
|
||||
|
||||
public ByteBuffer encode() {
|
||||
ByteBuffer data = ByteBuffer.allocate(2);
|
||||
addNetShort(data, 0x06);
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
116
src/com/projectswg/network/packets/soe/MultiPacket.java
Normal file
116
src/com/projectswg/network/packets/soe/MultiPacket.java
Normal file
@@ -0,0 +1,116 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.network.packets.soe;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.projectswg.network.packets.Packet;
|
||||
|
||||
|
||||
public class MultiPacket extends Packet {
|
||||
|
||||
private final List <byte []> content;
|
||||
|
||||
public MultiPacket() {
|
||||
this(new ArrayList<>());
|
||||
}
|
||||
|
||||
public MultiPacket(ByteBuffer data) {
|
||||
this(new ArrayList<>());
|
||||
decode(data);
|
||||
}
|
||||
|
||||
public MultiPacket(List <byte []> packets) {
|
||||
this.content = packets;
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer data) {
|
||||
super.decode(data);
|
||||
data.position(2);
|
||||
int pLength = getNextPacketLength(data);
|
||||
while (data.remaining() >= pLength && pLength > 0) {
|
||||
byte [] pData = new byte[pLength];
|
||||
data.get(pData);
|
||||
content.add(pData);
|
||||
pLength = getNextPacketLength(data);
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBuffer encode() {
|
||||
int length = getLength();
|
||||
ByteBuffer data = ByteBuffer.allocate(length);
|
||||
addNetShort(data, 3);
|
||||
for (byte [] packet : content) {
|
||||
if (packet.length >= 255) {
|
||||
addByte(data, 255);
|
||||
addShort(data, packet.length);
|
||||
} else {
|
||||
addByte(data, packet.length);
|
||||
}
|
||||
data.put(packet);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
int length = 2;
|
||||
for (byte [] packet : content) {
|
||||
length += packet.length + 1;
|
||||
if (packet.length >= 255)
|
||||
length += 2;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
public void addPacket(byte [] packet) {
|
||||
content.add(packet);
|
||||
}
|
||||
|
||||
public void clearPackets() {
|
||||
content.clear();
|
||||
}
|
||||
|
||||
public List <byte []> getPackets() {
|
||||
return content;
|
||||
}
|
||||
|
||||
private int getNextPacketLength(ByteBuffer data) {
|
||||
if (data.remaining() < 1)
|
||||
return 0;
|
||||
int length = getByte(data) & 0xFF;
|
||||
if (length == 255) {
|
||||
if (data.remaining() < 2)
|
||||
return 0;
|
||||
return getShort(data) & 0xFFFF;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
}
|
||||
65
src/com/projectswg/network/packets/soe/OutOfOrder.java
Normal file
65
src/com/projectswg/network/packets/soe/OutOfOrder.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.network.packets.soe;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.projectswg.network.packets.Packet;
|
||||
|
||||
|
||||
public class OutOfOrder extends Packet {
|
||||
|
||||
private short sequence;
|
||||
|
||||
public OutOfOrder() {
|
||||
|
||||
}
|
||||
|
||||
public OutOfOrder(short sequence) {
|
||||
this.sequence = sequence;
|
||||
}
|
||||
|
||||
public OutOfOrder(ByteBuffer data) {
|
||||
decode(data);
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer data) {
|
||||
super.decode(data);
|
||||
data.position(2);
|
||||
sequence = getNetShort(data);
|
||||
}
|
||||
|
||||
public ByteBuffer encode() {
|
||||
ByteBuffer data = ByteBuffer.allocate(4);
|
||||
addNetShort(data, 0x11);
|
||||
addNetShort(data, sequence);
|
||||
return data;
|
||||
}
|
||||
|
||||
public short getSequence() { return sequence; }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.projectswg.network.packets.soe;
|
||||
|
||||
public interface SequencedPacket extends Comparable<SequencedPacket> {
|
||||
short getSequence();
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.network.packets.soe;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.projectswg.network.packets.Packet;
|
||||
|
||||
|
||||
public class ServerNetworkStatusUpdate extends Packet {
|
||||
|
||||
private short clientTickCount = 0;
|
||||
private int serverSyncStampLong = 0;
|
||||
private long clientPacketsSent = 0;
|
||||
private long clientPacketsRecv = 0;
|
||||
private long serverPacketsSent = 0;
|
||||
private long serverPacketsRecv = 0;
|
||||
|
||||
public ServerNetworkStatusUpdate() {
|
||||
|
||||
}
|
||||
|
||||
public ServerNetworkStatusUpdate(ByteBuffer data) {
|
||||
decode(data);
|
||||
}
|
||||
|
||||
public ServerNetworkStatusUpdate(int clientTickCount, long clientSent, long clientRecv, long serverSent, long serverRecv) {
|
||||
this.clientTickCount = (short) clientTickCount;
|
||||
this.serverSyncStampLong = 0;
|
||||
this.clientPacketsSent = clientSent;
|
||||
this.clientPacketsRecv = clientRecv;
|
||||
this.serverPacketsSent = serverSent;
|
||||
this.serverPacketsRecv = serverRecv;
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer data) {
|
||||
super.decode(data);
|
||||
data.position(2);
|
||||
clientTickCount = getNetShort(data);
|
||||
serverSyncStampLong = getNetInt(data);
|
||||
clientPacketsSent = getNetLong(data);
|
||||
clientPacketsRecv = getNetLong(data);
|
||||
serverPacketsSent = getNetLong(data);
|
||||
serverPacketsRecv = getNetLong(data);
|
||||
}
|
||||
|
||||
public ByteBuffer encode() {
|
||||
ByteBuffer data = ByteBuffer.allocate(40);
|
||||
addNetShort(data, 8);
|
||||
addNetShort(data, clientTickCount);
|
||||
addNetInt( data, serverSyncStampLong);
|
||||
addNetLong( data, clientPacketsSent);
|
||||
addNetLong( data, clientPacketsRecv);
|
||||
addNetLong( data, serverPacketsSent);
|
||||
addNetLong( data, serverPacketsRecv);
|
||||
return data;
|
||||
}
|
||||
|
||||
public short getClientTickCount() { return clientTickCount; }
|
||||
public int getServerSyncStampLong() { return serverSyncStampLong; }
|
||||
public long getClientPacketsSent() { return clientPacketsSent; }
|
||||
public long getClientPacketsRecv() { return clientPacketsRecv; }
|
||||
public long getServerPacketsSent() { return serverPacketsSent; }
|
||||
public long getServerPacketsRecv() { return serverPacketsRecv; }
|
||||
|
||||
public void setClientTickCount(short tick) { this.clientTickCount = tick; }
|
||||
public void setServerSyncStampLong(int sync) { this.serverSyncStampLong = sync; }
|
||||
public void setClientPacketsSent(int sent) { this.clientPacketsSent = sent; }
|
||||
public void setClientPacketsRecv(int recv) { this.clientPacketsRecv = recv; }
|
||||
public void setServerPacketsSent(int sent) { this.serverPacketsSent = sent; }
|
||||
public void setServerPacketsRecv(int recv) { this.serverPacketsRecv = recv; }
|
||||
}
|
||||
76
src/com/projectswg/network/packets/soe/SessionRequest.java
Normal file
76
src/com/projectswg/network/packets/soe/SessionRequest.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.network.packets.soe;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import com.projectswg.network.packets.Packet;
|
||||
|
||||
|
||||
public class SessionRequest extends Packet {
|
||||
|
||||
private int crcLength;
|
||||
private int connectionID;
|
||||
private int udpSize;
|
||||
|
||||
public SessionRequest() {
|
||||
|
||||
}
|
||||
|
||||
public SessionRequest(ByteBuffer data) {
|
||||
decode(data);
|
||||
}
|
||||
|
||||
public SessionRequest(int crcLength, int connectionID, int udpSize) {
|
||||
this.crcLength = crcLength;
|
||||
this.connectionID = connectionID;
|
||||
this.udpSize = udpSize;
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer packet) {
|
||||
super.decode(packet);
|
||||
packet.position(2);
|
||||
crcLength = getNetInt(packet);
|
||||
connectionID = getNetInt(packet);
|
||||
udpSize = getNetInt(packet);
|
||||
}
|
||||
|
||||
public ByteBuffer encode() {
|
||||
ByteBuffer bb = ByteBuffer.allocate(14).order(ByteOrder.BIG_ENDIAN);
|
||||
addNetShort(bb, 1);
|
||||
addNetInt(bb, crcLength);
|
||||
addNetInt(bb, connectionID);
|
||||
addNetInt(bb, udpSize);
|
||||
return bb;
|
||||
}
|
||||
|
||||
public int getCrcLength() { return crcLength; }
|
||||
public int getConnectionID() { return connectionID; }
|
||||
public int getUdpSize() { return udpSize; }
|
||||
}
|
||||
103
src/com/projectswg/network/packets/soe/SessionResponse.java
Normal file
103
src/com/projectswg/network/packets/soe/SessionResponse.java
Normal file
@@ -0,0 +1,103 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2015 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* -------------------------------------------------------------------------------- *
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore 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 Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
***********************************************************************************/
|
||||
package com.projectswg.network.packets.soe;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import com.projectswg.network.packets.Packet;
|
||||
|
||||
|
||||
public class SessionResponse extends Packet {
|
||||
|
||||
private int connectionID;
|
||||
private int crcSeed;
|
||||
private byte crcLength;
|
||||
private byte encryptionFlag;
|
||||
private byte xorLength;
|
||||
private int udpSize;
|
||||
|
||||
public SessionResponse() {
|
||||
|
||||
}
|
||||
|
||||
public SessionResponse(ByteBuffer data) {
|
||||
decode(data);
|
||||
}
|
||||
|
||||
public SessionResponse(int connectionID,
|
||||
int crcSeed,
|
||||
byte crcLength,
|
||||
byte encryptionFlag,
|
||||
byte xorLength,
|
||||
int udpSize) {
|
||||
this.connectionID = connectionID;
|
||||
this.crcSeed = crcSeed;
|
||||
this.crcLength = crcLength;
|
||||
this.encryptionFlag = encryptionFlag;
|
||||
this.xorLength = xorLength;
|
||||
this.udpSize = udpSize;
|
||||
}
|
||||
|
||||
public void decode(ByteBuffer data) {
|
||||
super.decode(data);
|
||||
data.position(2);
|
||||
connectionID = getNetInt(data);
|
||||
crcSeed = getNetInt(data);
|
||||
crcLength = data.get();
|
||||
encryptionFlag = data.get();
|
||||
xorLength = data.get();
|
||||
udpSize = getNetInt(data);
|
||||
}
|
||||
|
||||
public ByteBuffer encode() {
|
||||
ByteBuffer bb = ByteBuffer.allocate(17).order(ByteOrder.BIG_ENDIAN);
|
||||
addNetShort(bb, 2);
|
||||
addNetInt( bb, connectionID);
|
||||
addNetInt( bb, crcSeed);
|
||||
addByte( bb, crcLength);
|
||||
addByte( bb, encryptionFlag);
|
||||
addByte( bb, xorLength);
|
||||
addNetInt( bb, udpSize);
|
||||
return bb;
|
||||
}
|
||||
|
||||
public int getConnectionID() { return connectionID; }
|
||||
public int getCrcSeed() { return crcSeed; }
|
||||
public byte getCrcLength() { return crcLength; }
|
||||
public byte getEncryptionFlag() { return encryptionFlag; }
|
||||
public byte getXorLength() { return xorLength; }
|
||||
public int getUdpSize() { return udpSize; }
|
||||
|
||||
public void setConnectionID(int id) { this.connectionID = id; }
|
||||
public void setCrcSeed(int crc) { this.crcSeed = crc; }
|
||||
public void setCrcLength(int length) { this.crcLength = (byte) length; }
|
||||
public void setEncryptionFlag(short flag) { this.encryptionFlag = (byte) flag; }
|
||||
public void setXorLength(byte xorLength) { this.xorLength = xorLength; }
|
||||
public void setUdpSize(int size) { this.udpSize = size; }
|
||||
}
|
||||
46
src/com/projectswg/packets/ObjectSearcher.java
Normal file
46
src/com/projectswg/packets/ObjectSearcher.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package com.projectswg.packets;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import resources.objects.SWGObject;
|
||||
|
||||
import com.projectswg.PacketMasterData;
|
||||
|
||||
public class ObjectSearcher extends Searcher {
|
||||
|
||||
private final PacketMasterData data;
|
||||
private List<SWGObject> objects;
|
||||
private SWGObject lastMatch;
|
||||
|
||||
public ObjectSearcher(PacketMasterData data) {
|
||||
this.data = data;
|
||||
this.objects = null;
|
||||
}
|
||||
|
||||
public SWGObject getLastMatch() {
|
||||
return lastMatch;
|
||||
}
|
||||
|
||||
protected int getSize() {
|
||||
return data.getData().getObjects().size();
|
||||
}
|
||||
|
||||
protected void initializeSearch(String search) {
|
||||
objects = data.getData().getObjects();
|
||||
}
|
||||
|
||||
protected void terminateSearch() {
|
||||
|
||||
}
|
||||
|
||||
protected boolean isMatch(int index, String search) {
|
||||
SWGObject obj = objects.get(index);
|
||||
String name = obj.getClass().getCanonicalName();
|
||||
boolean match = name != null && name.toLowerCase(Locale.US).contains(search.toLowerCase(Locale.US));
|
||||
if (match)
|
||||
lastMatch = obj;
|
||||
return match;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,63 +1,99 @@
|
||||
package com.projectswg.packets;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import network.packets.Packet;
|
||||
import network.packets.swg.zone.SceneCreateObjectByCrc;
|
||||
import network.packets.swg.zone.UpdateContainmentMessage;
|
||||
import network.packets.swg.zone.UpdatePvpStatusMessage;
|
||||
import network.packets.swg.zone.baselines.Baseline;
|
||||
import network.packets.swg.zone.insertion.CmdStartScene;
|
||||
import resources.objects.SWGObject;
|
||||
import resources.objects.tangible.TangibleObject;
|
||||
import resources.server_info.CrcDatabase;
|
||||
import services.objects.ObjectCreator;
|
||||
|
||||
import com.projectswg.gui.GUIPacket;
|
||||
|
||||
public class PacketData {
|
||||
|
||||
private static final CrcDatabase CRC_DATABASE = new CrcDatabase();
|
||||
|
||||
private final LinkedHashMap<Long, SWGObject> objects;
|
||||
|
||||
private List<GUIPacket> packets;
|
||||
private InetAddress client;
|
||||
private InetAddress server;
|
||||
private InetSocketAddress server;
|
||||
private int selectedIndex;
|
||||
private long selectedId;
|
||||
|
||||
public PacketData() {
|
||||
objects = new LinkedHashMap<>();
|
||||
packets = new ArrayList<>();
|
||||
client = null;
|
||||
server = null;
|
||||
selectedIndex = 0;
|
||||
selectedId = 0;
|
||||
}
|
||||
|
||||
public void addPacket(GUIPacket packet) {
|
||||
packets.add(packet);
|
||||
if (packet.getPacket() == null)
|
||||
throw new NullPointerException();
|
||||
synchronized (packets) {
|
||||
packets.add(packet);
|
||||
}
|
||||
processPacket(packet.getPacket());
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
packets.clear();
|
||||
synchronized (packets) {
|
||||
packets.clear();
|
||||
}
|
||||
synchronized (objects) {
|
||||
objects.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public GUIPacket get(int index) {
|
||||
return packets.get(index);
|
||||
synchronized (packets) {
|
||||
return packets.get(index);
|
||||
}
|
||||
}
|
||||
|
||||
public List<GUIPacket> getPackets() {
|
||||
return Collections.unmodifiableList(packets);
|
||||
synchronized (packets) {
|
||||
return new ArrayList<>(packets);
|
||||
}
|
||||
}
|
||||
|
||||
public List<SWGObject> getObjects() {
|
||||
return new ArrayList<>(objects.values());
|
||||
}
|
||||
|
||||
public SWGObject getObject(long objectId) {
|
||||
return objects.get(objectId);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return packets.size();
|
||||
synchronized (packets) {
|
||||
return packets.size();
|
||||
}
|
||||
}
|
||||
|
||||
public int getSelectedIndex() {
|
||||
return selectedIndex;
|
||||
}
|
||||
|
||||
public InetAddress getClient() {
|
||||
return client;
|
||||
public long getSelectedId() {
|
||||
return selectedId;
|
||||
}
|
||||
|
||||
public InetAddress getServer() {
|
||||
public InetSocketAddress getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public void setClient(InetAddress client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public void setServer(InetAddress server) {
|
||||
public void setServer(InetSocketAddress server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@@ -65,12 +101,91 @@ public class PacketData {
|
||||
this.selectedIndex = index;
|
||||
}
|
||||
|
||||
public boolean isClient(InetAddress addr) {
|
||||
return client != null && client.equals(addr);
|
||||
public void setSelectedId(long id) {
|
||||
this.selectedId = id;
|
||||
}
|
||||
|
||||
public boolean isServer(InetAddress addr) {
|
||||
public boolean isServer(InetSocketAddress addr) {
|
||||
return server != null && server.equals(addr);
|
||||
}
|
||||
|
||||
public boolean isServerDefined() {
|
||||
return server != null;
|
||||
}
|
||||
|
||||
private void processPacket(Packet p) {
|
||||
if (p instanceof SceneCreateObjectByCrc)
|
||||
processCreateObject((SceneCreateObjectByCrc) p);
|
||||
else if (p instanceof CmdStartScene)
|
||||
processCmdStartScene((CmdStartScene) p);
|
||||
else if (p instanceof UpdateContainmentMessage)
|
||||
processUpdateContainment((UpdateContainmentMessage) p);
|
||||
else if (p instanceof UpdatePvpStatusMessage)
|
||||
processUpdatePvpStatus((UpdatePvpStatusMessage) p);
|
||||
else if (p instanceof Baseline)
|
||||
processBaseline((Baseline) p);
|
||||
}
|
||||
|
||||
private void processCreateObject(SceneCreateObjectByCrc create) {
|
||||
String template = CRC_DATABASE.getString(create.getObjectCrc());
|
||||
SWGObject obj = null;
|
||||
if (template != null)
|
||||
obj = ObjectCreator.createObjectFromTemplate(create.getObjectId(), template);
|
||||
if (obj != null) {
|
||||
obj.setLocation(create.getLocation());
|
||||
SWGObject recreate = objects.put(obj.getObjectId(), obj);
|
||||
if (recreate != null) {
|
||||
System.err.println("Recreating " + recreate.getTemplate() + " with " + template);
|
||||
}
|
||||
} else
|
||||
System.err.println("Failed to create: " + template);
|
||||
}
|
||||
|
||||
private void processCmdStartScene(CmdStartScene start) {
|
||||
objects.clear();
|
||||
String template = start.getRace().getFilename();
|
||||
SWGObject obj = ObjectCreator.createObjectFromTemplate(start.getCharacterId(), template);
|
||||
if (obj != null) {
|
||||
obj.setLocation(start.getLocation());
|
||||
objects.put(obj.getObjectId(), obj);
|
||||
} else
|
||||
System.err.println("Failed to create: " + template);
|
||||
}
|
||||
|
||||
private void processUpdateContainment(UpdateContainmentMessage update) {
|
||||
SWGObject obj = objects.get(update.getObjectId());
|
||||
if (obj == null) {
|
||||
System.err.println("No such ID for update containment! ID: " + update.getObjectId());
|
||||
return;
|
||||
}
|
||||
SWGObject parent = objects.get(update.getContainerId());
|
||||
if (parent == null) {
|
||||
System.err.println("Unkown parent! ID: " + update.getObjectId() + " Parent: " + update.getContainerId());
|
||||
}
|
||||
obj.setParent(parent);
|
||||
if (parent != null)
|
||||
parent.addObject(obj);
|
||||
}
|
||||
|
||||
private void processUpdatePvpStatus(UpdatePvpStatusMessage update) {
|
||||
SWGObject obj = objects.get(update.getObjectId());
|
||||
if (obj == null) {
|
||||
System.err.printf("No such ID for update pvp! ID: %d [%16X]%n", update.getObjectId(), update.getObjectId());
|
||||
return;
|
||||
}
|
||||
if (!(obj instanceof TangibleObject)) {
|
||||
System.err.println("Object is not a tangible object! Cannot set pvp flags: " + obj);
|
||||
return;
|
||||
}
|
||||
((TangibleObject) obj).setPvpFlags(update.getPvpFlags());
|
||||
}
|
||||
|
||||
private void processBaseline(Baseline baseline) {
|
||||
SWGObject obj = objects.get(baseline.getObjectId());
|
||||
if (obj != null)
|
||||
obj.parseBaseline(baseline);
|
||||
else
|
||||
System.err.println("Baseline for object not created! ID: " + baseline.getObjectId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,43 @@
|
||||
package com.projectswg.packets;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.jnetpcap.Pcap;
|
||||
import org.jnetpcap.PcapBpfProgram;
|
||||
import org.jnetpcap.nio.JBuffer;
|
||||
import org.jnetpcap.packet.Payload;
|
||||
import org.jnetpcap.packet.PcapPacket;
|
||||
import org.jnetpcap.packet.PcapPacketHandler;
|
||||
import org.jnetpcap.protocol.lan.Ethernet;
|
||||
import org.jnetpcap.protocol.network.Ip4;
|
||||
import org.jnetpcap.protocol.tcpip.Udp;
|
||||
|
||||
import utilities.ThreadUtilities;
|
||||
|
||||
public class PacketInterface {
|
||||
|
||||
private final Queue<InterfacePacket> packetQueue;
|
||||
private PacketInterfaceCallback callback;
|
||||
private PacketAnalysisThread analysis;
|
||||
private boolean isLive;
|
||||
|
||||
public PacketInterface() {
|
||||
packetQueue = new ArrayDeque<>();
|
||||
analysis = null;
|
||||
callback = null;
|
||||
}
|
||||
@@ -25,27 +46,56 @@ public class PacketInterface {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public boolean isLive() {
|
||||
return isLive;
|
||||
}
|
||||
|
||||
public void openLive(String inter) {
|
||||
if (analysis != null)
|
||||
analysis.stop();
|
||||
stop();
|
||||
synchronized (packetQueue) {
|
||||
packetQueue.clear();
|
||||
}
|
||||
analysis = new LivePacketAnalysis(inter);
|
||||
isLive = true;
|
||||
analysis.start();
|
||||
}
|
||||
|
||||
public void openFile(String file) {
|
||||
if (analysis != null)
|
||||
analysis.stop();
|
||||
stop();
|
||||
synchronized (packetQueue) {
|
||||
packetQueue.clear();
|
||||
}
|
||||
analysis = new FilePacketAnalysis(file);
|
||||
isLive = false;
|
||||
analysis.start();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (analysis != null) {
|
||||
System.out.println("Stopping old analysis! Type: " + analysis);
|
||||
analysis.stop();
|
||||
analysis.awaitTermination();
|
||||
analysis = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
if (isLive())
|
||||
throw new IllegalStateException("Cannot restart when live capturing");
|
||||
if (analysis == null)
|
||||
throw new IllegalStateException("Cannot restart when wasn't started in the first place");
|
||||
if (!(analysis instanceof FilePacketAnalysis))
|
||||
throw new IllegalStateException("Internal error... not sure how this happens");
|
||||
openFile(((FilePacketAnalysis) analysis).getFile());
|
||||
}
|
||||
|
||||
public void saveFile(String file) {
|
||||
|
||||
}
|
||||
|
||||
public interface PacketInterfaceCallback {
|
||||
void onCaptureStarted();
|
||||
void onPacket(InetAddress addr, int source, int destination, Date time, byte [] data);
|
||||
void onPacket(InterfacePacket packet);
|
||||
void onCaptureFinished();
|
||||
}
|
||||
|
||||
@@ -61,14 +111,21 @@ public class PacketInterface {
|
||||
final StringBuilder errbuf = new StringBuilder(); // For any error msgs
|
||||
System.out.println("Opening "+inter+" for live capture");
|
||||
Pcap pcap = Pcap.openLive(inter, 1024, Pcap.MODE_PROMISCUOUS, 60000, errbuf);
|
||||
if (pcap == null) {
|
||||
System.err.println("Error while opening device for capture: " + errbuf.toString());
|
||||
System.err.println("Interface: " + inter);
|
||||
return;
|
||||
try {
|
||||
if (pcap == null) {
|
||||
System.err.println("Error while opening device for capture: " + errbuf.toString());
|
||||
System.err.println("Interface: " + inter);
|
||||
return;
|
||||
}
|
||||
runAnalysis(pcap, true);
|
||||
} finally {
|
||||
pcap.close();
|
||||
System.out.println("Finished live capture.");
|
||||
}
|
||||
runAnalysis(pcap, true);
|
||||
pcap.close();
|
||||
System.out.println("Finished live capture.");
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "LivePacketAnalysis['"+inter+"']";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -81,23 +138,92 @@ public class PacketInterface {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
String extension = file.substring(file.lastIndexOf('.')+1);
|
||||
switch (extension) {
|
||||
case "pcap":
|
||||
case "cap":
|
||||
runPcap();
|
||||
break;
|
||||
case "hcap":
|
||||
runHcap();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void runPcap() {
|
||||
final StringBuilder errbuf = new StringBuilder(); // For any error msgs
|
||||
Pcap pcap = Pcap.openOffline(file, errbuf);
|
||||
if (pcap == null) {
|
||||
System.err.println("Error while opening file for capture: " + errbuf.toString());
|
||||
System.err.println("File: " + file);
|
||||
return;
|
||||
try {
|
||||
if (pcap == null) {
|
||||
System.err.println("Error while opening file for capture: " + errbuf.toString());
|
||||
System.err.println("File: " + file);
|
||||
return;
|
||||
}
|
||||
runAnalysis(pcap, false);
|
||||
} finally {
|
||||
pcap.close();
|
||||
System.out.println("Finished offline capture.");
|
||||
}
|
||||
runAnalysis(pcap, false);
|
||||
pcap.close();
|
||||
System.out.println("Finished offline capture.");
|
||||
}
|
||||
|
||||
private void runHcap() {
|
||||
ExecutorService callbackExecutor = Executors.newSingleThreadExecutor(ThreadUtilities.newThreadFactory(toString()+"-CallbackExecutor"));
|
||||
try (DataInputStream dataIn = new DataInputStream(new FileInputStream(new File(file)))) {
|
||||
initAnalysis(callbackExecutor);
|
||||
int version = dataIn.readByte();
|
||||
switch (version) {
|
||||
case 1:
|
||||
runHcap1(callbackExecutor, dataIn);
|
||||
break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
cleanupAnalysis(callbackExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
private void runHcap1(ExecutorService callbackExecutor, DataInputStream dataIn) throws IOException {
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
int count = dataIn.readByte();
|
||||
for (int i = 0; i < count; i++) {
|
||||
String [] property = dataIn.readUTF().split("=", 2);
|
||||
properties.put(property[0], property[1]);
|
||||
}
|
||||
while (dataIn.available() > 0) {
|
||||
dataIn.readByte(); // isServer
|
||||
Date time = new Date(dataIn.readLong());
|
||||
InetSocketAddress source = readSocket(dataIn);
|
||||
InetSocketAddress destination = readSocket(dataIn);
|
||||
byte [] data = new byte[dataIn.readShort() & 0xFFFF];
|
||||
dataIn.read(data);
|
||||
addPacket(new InterfacePacket(source, destination, time, data, InterfaceType.FILE_HCAP));
|
||||
processPacket(callbackExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
private InetSocketAddress readSocket(DataInputStream dataIn) throws IOException {
|
||||
int length = dataIn.readByte();
|
||||
byte [] addr = new byte[length];
|
||||
dataIn.read(addr);
|
||||
int port = dataIn.readShort() & 0xFFFF;
|
||||
return new InetSocketAddress(InetAddress.getByAddress(addr), port);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "FilePacketAnalysis['"+file+"']";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private abstract class PacketAnalysisThread implements Runnable {
|
||||
|
||||
private final AtomicBoolean analysisRunning = new AtomicBoolean(false);
|
||||
private Thread thread = null;
|
||||
private boolean running = false;
|
||||
|
||||
@@ -114,43 +240,175 @@ public class PacketInterface {
|
||||
return;
|
||||
running = false;
|
||||
thread.interrupt();
|
||||
}
|
||||
|
||||
public void awaitTermination() {
|
||||
while (analysisRunning.get()) {
|
||||
try {
|
||||
Thread.sleep(5);
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
thread = null;
|
||||
}
|
||||
|
||||
protected void runAnalysis(Pcap pcap, boolean live) {
|
||||
PcapPacket packet = new PcapPacket(500);
|
||||
ExecutorService callbackExecutor = Executors.newSingleThreadExecutor(ThreadUtilities.newThreadFactory(toString()+"-CallbackExecutor"));
|
||||
Udp udp = new Udp();
|
||||
Ip4 ip = new Ip4();
|
||||
if (callback != null)
|
||||
callback.onCaptureStarted();
|
||||
while (running && (pcap.nextEx(packet) >= 0 || live)) {
|
||||
if (packet == null)
|
||||
try {
|
||||
initAnalysis(callbackExecutor);
|
||||
PcapBpfProgram program = new PcapBpfProgram();
|
||||
if (pcap.compile(program, "udp", 0, 0xFFFFFF00) != Pcap.OK) {
|
||||
System.err.println(pcap.getErr());
|
||||
return;
|
||||
if (!packet.hasHeader(ip))
|
||||
continue;
|
||||
if (!packet.hasHeader(udp))
|
||||
continue;
|
||||
try {
|
||||
process(packet, ip, udp);
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (pcap.setFilter(program) != Pcap.OK) {
|
||||
System.err.println(pcap.getErr());
|
||||
return;
|
||||
}
|
||||
pcap.loop(-1, (PcapPacketHandler<String>) (packet, arg) -> {
|
||||
if (!running)
|
||||
pcap.breakloop();
|
||||
int headerRet = processHeaders(packet, udp, ip);
|
||||
if (headerRet == -1)
|
||||
pcap.breakloop();
|
||||
else if (headerRet == 0)
|
||||
process(callbackExecutor, packet, udp, ip, live ? InterfaceType.LIVE : InterfaceType.FILE_PCAP);
|
||||
else
|
||||
System.err.println("Failed to process packet with code: " + headerRet);
|
||||
}, "");
|
||||
} finally {
|
||||
cleanupAnalysis(callbackExecutor);
|
||||
}
|
||||
if (callback != null)
|
||||
callback.onCaptureFinished();
|
||||
}
|
||||
|
||||
private void process(PcapPacket packet, Ip4 ip, Udp udp) throws UnknownHostException {
|
||||
Payload p = new Payload();
|
||||
InetAddress addr = InetAddress.getByAddress(ip.source());
|
||||
int source = udp.source();
|
||||
int destination = udp.destination();
|
||||
JBuffer buffer = packet.getHeader(p);
|
||||
Date time = new Date(packet.getCaptureHeader().timestampInMillis());
|
||||
protected void initAnalysis(ExecutorService callbackExecutor) {
|
||||
analysisRunning.set(true);
|
||||
if (callback != null) {
|
||||
callbackExecutor.execute(() -> {
|
||||
try {
|
||||
callback.onCaptureStarted();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected void addPacket(InterfacePacket packet) {
|
||||
synchronized (packetQueue) {
|
||||
packetQueue.add(packet);
|
||||
}
|
||||
}
|
||||
|
||||
protected void processPacket(ExecutorService callbackExecutor) {
|
||||
callbackExecutor.execute(() -> {
|
||||
InterfacePacket raw = null;
|
||||
synchronized (packetQueue) {
|
||||
raw = packetQueue.poll();
|
||||
}
|
||||
if (raw == null) {
|
||||
System.err.println("No packet to process! Queue is empty.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (callback != null)
|
||||
callback.onPacket(raw);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void cleanupAnalysis(ExecutorService callbackExecutor) {
|
||||
running = false;
|
||||
thread = null;
|
||||
if (analysis == this)
|
||||
analysis = null;
|
||||
if (callback != null)
|
||||
callback.onPacket(addr, source, destination, time, buffer.getByteArray(0, new byte[buffer.size()]));
|
||||
callbackExecutor.execute(() -> {
|
||||
try {
|
||||
callback.onCaptureFinished();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
callbackExecutor.shutdown();
|
||||
try {
|
||||
callbackExecutor.awaitTermination(5, TimeUnit.MINUTES);
|
||||
} catch (InterruptedException e) {
|
||||
callbackExecutor.shutdownNow();
|
||||
}
|
||||
analysisRunning.set(false);
|
||||
}
|
||||
|
||||
private void process(ExecutorService callbackExecutor, PcapPacket packet, Udp udp, Ip4 ip, InterfaceType type) {
|
||||
try {
|
||||
process(packet, ip, udp, type);
|
||||
processPacket(callbackExecutor);
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private int processHeaders(PcapPacket packet, Udp udp, Ip4 ip) {
|
||||
try {
|
||||
packet.scan(Ethernet.ID);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
if (!packet.hasHeader(ip))
|
||||
return 2;
|
||||
if (!packet.hasHeader(udp))
|
||||
return 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void process(PcapPacket packet, Ip4 ip, Udp udp, InterfaceType type) throws UnknownHostException {
|
||||
Payload p = new Payload();
|
||||
InetSocketAddress source = new InetSocketAddress(InetAddress.getByAddress(ip.source()), udp.source());
|
||||
InetSocketAddress destination = new InetSocketAddress(InetAddress.getByAddress(ip.destination()), udp.destination());
|
||||
JBuffer buffer = packet.getHeader(p);
|
||||
if (buffer == null) {
|
||||
System.err.println("JBuffer is null! Dropping packet");
|
||||
return;
|
||||
}
|
||||
Date time = new Date(packet.getCaptureHeader().timestampInMillis());
|
||||
addPacket(new InterfacePacket(source, destination, time, buffer.getByteArray(0, new byte[buffer.size()]), type));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class InterfacePacket {
|
||||
|
||||
private final InetSocketAddress source;
|
||||
private final InetSocketAddress destination;
|
||||
private final Date time;
|
||||
private final byte [] data;
|
||||
private final InterfaceType type;
|
||||
|
||||
public InterfacePacket(InetSocketAddress source, InetSocketAddress destination, Date time, byte [] data, InterfaceType type) {
|
||||
this.destination = destination;
|
||||
this.source = source;
|
||||
this.time = time;
|
||||
this.data = data;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public InetSocketAddress getSource() { return source; }
|
||||
public InetSocketAddress getDestination() { return destination; }
|
||||
public Date getTime() { return time; }
|
||||
public byte[] getData() { return data; }
|
||||
public InterfaceType getType() { return type; }
|
||||
}
|
||||
|
||||
public enum InterfaceType {
|
||||
LIVE,
|
||||
FILE_PCAP,
|
||||
FILE_HCAP
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
206
src/com/projectswg/packets/PacketPipeProcessor.java
Normal file
206
src/com/projectswg/packets/PacketPipeProcessor.java
Normal file
@@ -0,0 +1,206 @@
|
||||
package com.projectswg.packets;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
import network.packets.Packet;
|
||||
|
||||
import com.projectswg.network.packets.soe.DataChannel;
|
||||
import com.projectswg.network.packets.soe.Fragmented;
|
||||
import com.projectswg.network.packets.soe.SequencedPacket;
|
||||
|
||||
public class PacketPipeProcessor {
|
||||
|
||||
private List <SequencedPacket> sequenced;
|
||||
private Queue <ProcessedPacket> processed;
|
||||
private short sequence;
|
||||
|
||||
public PacketPipeProcessor() {
|
||||
sequenced = new ArrayList<>();
|
||||
processed = new LinkedList<>();
|
||||
sequence = -1;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
System.out.println("RESET");
|
||||
sequence = -1;
|
||||
synchronized (sequenced) {
|
||||
sequenced.clear();
|
||||
}
|
||||
synchronized (processed) {
|
||||
processed.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void setMinSequence(short sequence) {
|
||||
if (this.sequence < 0) {
|
||||
this.sequence = sequence;
|
||||
System.out.println("Min Seq: " + sequence);
|
||||
processSequenced();
|
||||
} else {
|
||||
// System.out.println("*");
|
||||
// while (!sequenced.isEmpty() && sequenced.get(0).getSequence() < sequence) {
|
||||
// this.sequence = (short) (sequenced.get(0).getSequence() - 1);
|
||||
// System.out.println(sequenced.get(0).getSequence() + " / " + sequence + "-"+this.sequence+" [" + sequenced.size() + "]");
|
||||
// processSequenced();
|
||||
// }
|
||||
// this.sequence = sequence;
|
||||
// processSequenced();
|
||||
}
|
||||
}
|
||||
|
||||
public ProcessedPacket poll() {
|
||||
synchronized (processed) {
|
||||
return processed.poll();
|
||||
}
|
||||
}
|
||||
|
||||
public void feed(Packet p) {
|
||||
if (p instanceof SequencedPacket) {
|
||||
handleSequencedPacket((SequencedPacket) p);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSequencedPacket(SequencedPacket p) {
|
||||
synchronized (sequenced) {
|
||||
sequenced.add(p);
|
||||
Collections.sort(sequenced);
|
||||
processSequenced();
|
||||
}
|
||||
}
|
||||
|
||||
private void processSequenced() {
|
||||
short prevSequence = sequence;
|
||||
do {
|
||||
prevSequence = sequence;
|
||||
processDataChannel();
|
||||
processFragmented();
|
||||
} while (sequence != prevSequence);
|
||||
}
|
||||
|
||||
private void processDataChannel() {
|
||||
while (!sequenced.isEmpty()) {
|
||||
SequencedPacket sp = sequenced.get(0);
|
||||
int comp = Short.compare(sp.getSequence(), (short)(sequence+1));
|
||||
if (comp > 0 || !(sp instanceof DataChannel)) {
|
||||
System.out.println("> " + sp.getSequence() + " " + (sequence+1));
|
||||
break;
|
||||
}
|
||||
sequenced.remove(0);
|
||||
if (comp < 0) {
|
||||
System.out.println("< " + sp.getSequence() + " " + (sequence+1));
|
||||
continue;
|
||||
}
|
||||
sequence++;
|
||||
System.out.println("PRC " + sp.getSequence());
|
||||
processDataChannel((DataChannel) sp);
|
||||
}
|
||||
}
|
||||
|
||||
private void processFragmented() {
|
||||
while (!sequenced.isEmpty()) {
|
||||
if (!isFragmentedReady())
|
||||
break;
|
||||
SequencedPacket sp = sequenced.get(0);
|
||||
int comp = Short.compare(sp.getSequence(), (short)(sequence+1));
|
||||
if (comp > 0 || !(sp instanceof Fragmented))
|
||||
break;
|
||||
sequenced.remove(0);
|
||||
if (comp < 0)
|
||||
continue;
|
||||
sequence++;
|
||||
Fragmented f = (Fragmented) sp;
|
||||
ByteBuffer combined = ByteBuffer.allocate(getFragmentedSize(f));
|
||||
f.getPacketData().position(8);
|
||||
combined.put(f.getPacketData());
|
||||
processRemainingFragmented(combined);
|
||||
synchronized (processed) {
|
||||
processed.add(new ProcessedPacket(f.getAddress(), f.getPort(), f.getTime(), combined.array()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processRemainingFragmented(ByteBuffer combined) {
|
||||
while (combined.hasRemaining()) {
|
||||
SequencedPacket sp = sequenced.get(0);
|
||||
int comp = Short.compare(sp.getSequence(), (short)(sequence+1));
|
||||
if (comp > 0 || !(sp instanceof Fragmented))
|
||||
break;
|
||||
sequenced.remove(0);
|
||||
if (comp < 0)
|
||||
continue;
|
||||
sequence++;
|
||||
Fragmented f = (Fragmented) sp;
|
||||
f.getPacketData().position(4);
|
||||
combined.put(f.getPacketData());
|
||||
}
|
||||
}
|
||||
|
||||
private void processDataChannel(DataChannel data) {
|
||||
synchronized (processed) {
|
||||
for (byte [] inner : data.getPackets()) {
|
||||
processed.add(new ProcessedPacket(data.getAddress(), data.getPort(), data.getTime(), inner));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFragmentedReady() {
|
||||
short seq = sequence;
|
||||
int size = 0, index = 0;
|
||||
for (SequencedPacket sp : sequenced) {
|
||||
int comp = Short.compare(sp.getSequence(), (short) (seq+1));
|
||||
if (comp < 0)
|
||||
continue;
|
||||
if (comp > 0 || !(sp instanceof Fragmented))
|
||||
return false;
|
||||
seq++;
|
||||
Fragmented f = (Fragmented) sp;
|
||||
if (index == 0) {
|
||||
ByteBuffer data = f.getPacketData();
|
||||
data.position(4);
|
||||
size = Packet.getNetInt(data);
|
||||
index = data.remaining();
|
||||
} else {
|
||||
index += f.getPacketData().limit()-4;
|
||||
if (index >= size) {
|
||||
return index == size;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int getFragmentedSize(Fragmented f) {
|
||||
ByteBuffer data = f.getPacketData();
|
||||
data.position(4);
|
||||
return Packet.getNetInt(data);
|
||||
}
|
||||
|
||||
public static class ProcessedPacket {
|
||||
|
||||
private final InetAddress addr;
|
||||
private final int port;
|
||||
private final Date date;
|
||||
private final byte [] data;
|
||||
|
||||
private ProcessedPacket(InetAddress addr, int port, Date date, byte [] data) {
|
||||
this.addr = addr;
|
||||
this.port = port;
|
||||
this.date = date;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public InetAddress getAddress() { return addr; }
|
||||
public int getPort() { return port; }
|
||||
public Date getDate() { return date; }
|
||||
public byte[] getData() { return data; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +1,32 @@
|
||||
package com.projectswg.packets;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.projectswg.PacketMasterData;
|
||||
import com.projectswg.gui.GUIPacket;
|
||||
|
||||
import network.PacketType;
|
||||
import network.encryption.Encryption;
|
||||
import network.packets.Packet;
|
||||
import network.packets.soe.DataChannelA;
|
||||
import network.packets.soe.Fragmented;
|
||||
import network.packets.soe.MultiPacket;
|
||||
import network.packets.soe.SessionResponse;
|
||||
|
||||
import com.projectswg.network.packets.Packet;
|
||||
import com.projectswg.network.packets.soe.Acknowledge;
|
||||
import com.projectswg.network.packets.soe.ClientNetworkStatusUpdate;
|
||||
import com.projectswg.network.packets.soe.DataChannel;
|
||||
import com.projectswg.network.packets.soe.Disconnect;
|
||||
import com.projectswg.network.packets.soe.Fragmented;
|
||||
import com.projectswg.network.packets.soe.MultiPacket;
|
||||
import com.projectswg.network.packets.soe.OutOfOrder;
|
||||
import com.projectswg.network.packets.soe.ServerNetworkStatusUpdate;
|
||||
import com.projectswg.network.packets.soe.SessionRequest;
|
||||
import com.projectswg.network.packets.soe.SessionResponse;
|
||||
import com.projectswg.packets.PacketInterface.InterfacePacket;
|
||||
import com.projectswg.packets.PacketPipeProcessor.ProcessedPacket;
|
||||
|
||||
import network.packets.swg.SWGPacket;
|
||||
import network.packets.swg.holo.HoloConnectionStarted;
|
||||
import network.packets.swg.zone.object_controller.ObjectController;
|
||||
|
||||
public class PacketProcessor {
|
||||
@@ -24,32 +34,83 @@ public class PacketProcessor {
|
||||
private static final int REMOTE_PING_PORT = 44462;
|
||||
|
||||
private final PacketData packetData;
|
||||
private List <Fragmented> fragmented;
|
||||
private final PacketPipeProcessor clientProcessor;
|
||||
private final PacketPipeProcessor serverProcessor;
|
||||
private int crc;
|
||||
private boolean encrypted;
|
||||
|
||||
public PacketProcessor(PacketData packetData) {
|
||||
this.packetData = packetData;
|
||||
fragmented = new ArrayList<Fragmented>();
|
||||
public PacketProcessor(PacketMasterData packetData) {
|
||||
this.packetData = packetData.getData();
|
||||
clientProcessor = new PacketPipeProcessor();
|
||||
serverProcessor = new PacketPipeProcessor();
|
||||
encrypted = true;
|
||||
}
|
||||
|
||||
public boolean onPacket(InetAddress addr, Date time, byte [] data, int port) {
|
||||
public void reset() {
|
||||
clientProcessor.reset();
|
||||
serverProcessor.reset();
|
||||
}
|
||||
|
||||
public void onCaptureFinished() {
|
||||
|
||||
}
|
||||
|
||||
public boolean onPacket(InterfacePacket packet) throws CrcChangedException {
|
||||
switch (packet.getType()) {
|
||||
case LIVE:
|
||||
case FILE_PCAP:
|
||||
return processSonyCapture(packet);
|
||||
case FILE_HCAP:
|
||||
return processHcap(packet);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processHcap(InterfacePacket packet) {
|
||||
ByteBuffer data = ByteBuffer.wrap(packet.getData());
|
||||
data.position(2);
|
||||
int swgOpcode = Packet.getInt(data);
|
||||
data.position(0);
|
||||
process(packet.getSource(), packet.getTime(), swgOpcode, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean processSonyCapture(InterfacePacket packet) throws CrcChangedException {
|
||||
byte [] data = packet.getData();
|
||||
int length = data.length;
|
||||
int port = packet.getSource().getPort();
|
||||
Date time = packet.getTime();
|
||||
InetSocketAddress socket = packet.getSource();
|
||||
if (length < 2)
|
||||
return false;
|
||||
if (port != REMOTE_PING_PORT) {
|
||||
if (data[0] == 0 && data[1] == 1) {
|
||||
packetData.setClient(addr);
|
||||
packetData.addPacket(new GUIPacket(ByteBuffer.wrap(data), time, 1, port, true));
|
||||
SessionRequest request = new SessionRequest(ByteBuffer.wrap(data));
|
||||
packetData.addPacket(new GUIPacket(request, time, 1, port, true));
|
||||
reset();
|
||||
packetData.setServer(null);
|
||||
return true;
|
||||
} else if (data[0] == 0 && data[1] == 2) { // SessionResponse
|
||||
packetData.setServer(addr);
|
||||
packetData.addPacket(new GUIPacket(ByteBuffer.wrap(data), time, 2, port, false));
|
||||
processSessionResponse(data);
|
||||
SessionResponse response = new SessionResponse(ByteBuffer.wrap(data));
|
||||
encrypted = (response.getEncryptionFlag() != 0);
|
||||
packetData.addPacket(new GUIPacket(response, time, 2, port, false));
|
||||
crc = response.getCrcSeed();
|
||||
reset();
|
||||
packetData.setServer(socket);
|
||||
return true;
|
||||
} else {
|
||||
ByteBuffer decrypt = ByteBuffer.wrap(Encryption.decode(data, crc));
|
||||
if (data.length == 9) {
|
||||
int crc = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).getInt(1)^0x6CF9AF00; // AF F9 6C A1
|
||||
packetData.setServer(socket);
|
||||
if (this.crc != crc) {
|
||||
this.crc = crc;
|
||||
throw new CrcChangedException("CRC changed!");
|
||||
}
|
||||
}
|
||||
ByteBuffer decrypt = encrypted ? ByteBuffer.wrap(Encryption.decode(data, crc)) : ByteBuffer.wrap(data);
|
||||
if (decrypt.array().length >= 2) {
|
||||
process(addr, decrypt, time, port);
|
||||
process(socket, decrypt, time);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -57,111 +118,59 @@ public class PacketProcessor {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void process(InetAddress addr, ByteBuffer data, Date time, int port) {
|
||||
if (data.remaining() < 2)
|
||||
private void process(InetSocketAddress socket, ByteBuffer data, Date time) {
|
||||
if (data.limit() < 2)
|
||||
return;
|
||||
data.position(0);
|
||||
int opcode = data.order(ByteOrder.BIG_ENDIAN).getShort() & 0xFFFF;
|
||||
data.position(data.position()-2);
|
||||
Packet packet = createPacket(data);
|
||||
if (packet != null) {
|
||||
packetData.addPacket(new GUIPacket(packet, time, opcode, socket.getPort(), !packetData.isServer(socket)));
|
||||
packet.setAddress(socket.getAddress());
|
||||
packet.setPort(socket.getPort());
|
||||
packet.setTime(time);
|
||||
}
|
||||
switch (opcode) {
|
||||
case 3: {
|
||||
MultiPacket multi = new MultiPacket();
|
||||
multi.decode(data);
|
||||
packetData.addPacket(new GUIPacket(data, time, opcode, port, packetData.isClient(addr)));
|
||||
ByteBuffer pData;
|
||||
for (Packet p : multi.getPackets()) {
|
||||
pData = p.getData();
|
||||
pData.position(0);
|
||||
process(addr, pData, time, port);
|
||||
case 0x03: {
|
||||
for (byte [] pData: ((MultiPacket) packet).getPackets()) {
|
||||
process(socket, ByteBuffer.wrap(pData), time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
packetData.addPacket(new GUIPacket(data, time, opcode, port, packetData.isClient(addr)));
|
||||
processDataChannelA(addr, data, time, port);
|
||||
case 0x08:
|
||||
packetData.setServer(socket);
|
||||
break;
|
||||
case 13:
|
||||
packetData.addPacket(new GUIPacket(data, time, opcode, port, packetData.isClient(addr)));
|
||||
processFragmentedA(addr, data, time, port);
|
||||
case 0x15:
|
||||
if (packetData.isServer(socket)) {
|
||||
clientProcessor.setMinSequence(((Acknowledge) packet).getSequence());
|
||||
ingest(clientProcessor);
|
||||
} else {
|
||||
serverProcessor.setMinSequence(((Acknowledge) packet).getSequence());
|
||||
ingest(serverProcessor);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (opcode >= 0x1E && data.remaining() >= 6) {
|
||||
if ((opcode < 0 || opcode >= 0x1E) && data.limit() >= 6) {
|
||||
data.position(2);
|
||||
int swgOpcode = Packet.getInt(data);
|
||||
data.position(0);
|
||||
process(addr, time, swgOpcode, data, port);
|
||||
} else {
|
||||
packetData.addPacket(new GUIPacket(data, time, opcode, port, packetData.isClient(addr)));
|
||||
process(socket, time, swgOpcode, data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void processFragmentedA(InetAddress addr, ByteBuffer buf, Date time, int port) {
|
||||
Fragmented frag = new Fragmented(buf);
|
||||
boolean found = false;
|
||||
for (int i = 0; i < fragmented.size() && !found; i++) {
|
||||
if (fragmented.get(i).getSequence() > frag.getSequence()) {
|
||||
if (i > 0 && fragmented.get(i-1).getSequence() == frag.getSequence())
|
||||
fragmented.set(i-1, frag);
|
||||
else
|
||||
fragmented.add(i, frag);
|
||||
found = true;
|
||||
if (packet != null) {
|
||||
if (packetData.isServer(socket)) {
|
||||
serverProcessor.feed(packet);
|
||||
ingest(serverProcessor);
|
||||
} else {
|
||||
clientProcessor.feed(packet);
|
||||
ingest(clientProcessor);
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
fragmented.add(frag);
|
||||
frag = fragmented.get(0);
|
||||
ByteBuffer data = frag.getPacketData();
|
||||
if (data.limit() < 8)
|
||||
throw new IllegalStateException("Fragmented Packet has invalid size!");
|
||||
data.position(2);
|
||||
int lastSequence = Packet.getNetShort(data); // Sequence
|
||||
int size = Packet.getNetInt(data);
|
||||
int index = data.remaining()+4;
|
||||
int packets = 1;
|
||||
for (int i = 1; i < fragmented.size(); i++) {
|
||||
Fragmented f = fragmented.get(i);
|
||||
if (f.getSequence() != lastSequence+1)
|
||||
return;
|
||||
index += f.getPacketData().array().length-4;
|
||||
lastSequence = f.getSequence();
|
||||
packets++;
|
||||
if (index >= size)
|
||||
break;
|
||||
}
|
||||
if (index >= size && size > 4) {
|
||||
ByteBuffer combination = ByteBuffer.allocate(size);
|
||||
for (int i = 0; i < packets; i++) {
|
||||
byte [] pData = fragmented.get(0).getPacketData().array();
|
||||
if (i == 0) {
|
||||
if (combination.remaining() >= pData.length-8)
|
||||
combination.put(pData, 8, pData.length-8);
|
||||
else
|
||||
return;
|
||||
} else {
|
||||
if (combination.remaining() >= pData.length-4)
|
||||
combination.put(pData, 4, pData.length-4);
|
||||
else
|
||||
return;
|
||||
}
|
||||
fragmented.remove(0);
|
||||
}
|
||||
combination.position(0);
|
||||
process(addr, combination, time, port);
|
||||
}
|
||||
}
|
||||
|
||||
private void processDataChannelA(InetAddress addr, ByteBuffer buf, Date time, int port) {
|
||||
DataChannelA data = new DataChannelA(buf);
|
||||
List <SWGPacket> packets = data.getPackets();
|
||||
for (SWGPacket packet : packets) {
|
||||
ByteBuffer pData = packet.getData();
|
||||
pData.position(0);
|
||||
process(addr, time, packet.getSWGOpcode(), pData, port);
|
||||
}
|
||||
}
|
||||
|
||||
private void process(InetAddress addr, Date time, int opcode, ByteBuffer data, int port) {
|
||||
private void process(InetSocketAddress socket, Date time, int opcode, ByteBuffer data) {
|
||||
data.position(0);
|
||||
SWGPacket packet = null;
|
||||
if (opcode == ObjectController.CRC)
|
||||
@@ -169,16 +178,63 @@ public class PacketProcessor {
|
||||
else {
|
||||
packet = PacketType.getForCrc(opcode);
|
||||
}
|
||||
if (packet == null)
|
||||
return;
|
||||
data.position(0);
|
||||
if (packet == null) {
|
||||
packet = new SWGPacket();
|
||||
packet.decode(data);
|
||||
packet.setAddress(socket.getAddress());
|
||||
packet.setPort(socket.getPort());
|
||||
packetData.addPacket(new GUIPacket(packet, PacketType.fromCrc(opcode), time, opcode, socket.getPort(), !packetData.isServer(socket)));
|
||||
return;
|
||||
}
|
||||
if (packet instanceof HoloConnectionStarted)
|
||||
packetData.setServer(socket);
|
||||
packet.decode(data);
|
||||
packetData.addPacket(new GUIPacket(packet, PacketType.fromCrc(opcode), time, opcode, port, packetData.isClient(addr)));
|
||||
packet.setAddress(socket.getAddress());
|
||||
packet.setPort(socket.getPort());
|
||||
packetData.addPacket(new GUIPacket(packet, PacketType.fromCrc(opcode), time, opcode, socket.getPort(), !packetData.isServer(socket)));
|
||||
}
|
||||
|
||||
private void processSessionResponse(byte [] data) {
|
||||
SessionResponse res = new SessionResponse(ByteBuffer.wrap(data));
|
||||
crc = res.getCrcSeed();
|
||||
private Packet createPacket(ByteBuffer data) {
|
||||
if (data.limit() < 2)
|
||||
return null;
|
||||
ByteOrder original = data.order();
|
||||
short opcode = data.order(ByteOrder.BIG_ENDIAN).getShort();
|
||||
data.order(original);
|
||||
switch (opcode) {
|
||||
case 0x01: return new SessionRequest(data);
|
||||
case 0x02: return new SessionResponse(data);
|
||||
case 0x03: return new MultiPacket(data);
|
||||
case 0x05: return new Disconnect(data);
|
||||
case 0x07: return new ClientNetworkStatusUpdate(data);
|
||||
case 0x08: return new ServerNetworkStatusUpdate(data);
|
||||
case 0x09: return new DataChannel(data);
|
||||
case 0x0D: return new Fragmented(data);
|
||||
case 0x11: return new OutOfOrder(data);
|
||||
case 0x15: return new Acknowledge(data);
|
||||
default:
|
||||
if (opcode <= 0x1E)
|
||||
System.err.println("Unknown Packet: " + opcode);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void ingest(PacketPipeProcessor processor) {
|
||||
ProcessedPacket packet = processor.poll();
|
||||
while (packet != null) {
|
||||
process(new InetSocketAddress(packet.getAddress(), packet.getPort()), ByteBuffer.wrap(packet.getData()), packet.getDate());
|
||||
packet = processor.poll();
|
||||
}
|
||||
}
|
||||
|
||||
public static class CrcChangedException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public CrcChangedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,68 +3,35 @@ package com.projectswg.packets;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.projectswg.PacketMasterData;
|
||||
import com.projectswg.gui.GUIPacket;
|
||||
|
||||
import utilities.ByteUtilities;
|
||||
|
||||
public class PacketSearcher {
|
||||
public class PacketSearcher extends Searcher {
|
||||
|
||||
private final PacketData data;
|
||||
private final boolean searchSoe;
|
||||
private final boolean searchSwg;
|
||||
private final PacketMasterData data;
|
||||
private CompiledSearch compiled;
|
||||
|
||||
public PacketSearcher(PacketData data, boolean searchSoe, boolean searchSwg) {
|
||||
public PacketSearcher(PacketMasterData data) {
|
||||
this.data = data;
|
||||
this.searchSoe = searchSoe;
|
||||
this.searchSwg = searchSwg;
|
||||
compiled = null;
|
||||
}
|
||||
|
||||
public int searchForward(int start, String search) {
|
||||
return searchForward(start, search, true);
|
||||
protected int getSize() {
|
||||
return data.getData().getPackets().size();
|
||||
}
|
||||
|
||||
public int searchForward(int start, String search, boolean wrap) {
|
||||
int res = search(start, data.getPackets().size(), search);
|
||||
if (res != -1 || !wrap)
|
||||
return res;
|
||||
return search(0, start, search);
|
||||
protected void initializeSearch(String search) {
|
||||
compiled = new CompiledSearch(search, data.isSearchSoe(), data.isSearchSwg());
|
||||
}
|
||||
|
||||
public int searchBackward(int start, String search) {
|
||||
return searchBackward(start, search, true);
|
||||
protected void terminateSearch() {
|
||||
|
||||
}
|
||||
|
||||
public int searchBackward(int start, String search, boolean wrap) {
|
||||
int res = search(start, 0, search);
|
||||
if (res != -1 || !wrap)
|
||||
return res;
|
||||
return search(0, start, search);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches from [start, end). Which includes the starting index, but not
|
||||
* the ending index.
|
||||
* @param start the starting index
|
||||
* @param end the ending index
|
||||
* @return the index that the item was found
|
||||
*/
|
||||
public int search(int start, int end, String search) {
|
||||
return search(start, end, end > start, search);
|
||||
}
|
||||
|
||||
private int search(int start, int end, boolean forward, String search) {
|
||||
int inc = forward ? 1 : -1;
|
||||
int index = start;
|
||||
CompiledSearch compiled = new CompiledSearch(search, searchSoe, searchSwg);
|
||||
int size = data.getPackets().size();
|
||||
while ((forward && start < end) || (!forward && start > end)) {
|
||||
if (index < 0 || index >= size)
|
||||
break;
|
||||
if (compiled.matches(data.get(index)))
|
||||
return index;
|
||||
index += inc;
|
||||
}
|
||||
return -1;
|
||||
protected boolean isMatch(int index, String search) {
|
||||
return compiled.matches(data.getData().getPackets().get(index));
|
||||
}
|
||||
|
||||
private static class CompiledSearch {
|
||||
@@ -104,21 +71,23 @@ public class PacketSearcher {
|
||||
return true;
|
||||
byte [] data = packet.getData().array();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
if (findArray(data, ascii, i))
|
||||
if (findArray(data, ascii, i, false))
|
||||
return true;
|
||||
if (findArray(data, unicode, i))
|
||||
if (findArray(data, unicode, i, false))
|
||||
return true;
|
||||
if (findArray(data, byteSearch, i))
|
||||
if (findArray(data, byteSearch, i, true))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean findArray(byte [] data, byte [] search, int index) {
|
||||
private boolean findArray(byte [] data, byte [] search, int index, boolean caseSensitive) {
|
||||
int ind = 0;
|
||||
boolean match = true;
|
||||
for (ind = 0; ind < search.length && index+ind < data.length && match; ind++) {
|
||||
if (search[ind] != Character.toLowerCase(data[index+ind]))
|
||||
if (!caseSensitive && search[ind] != Character.toLowerCase(data[index+ind]))
|
||||
match = false;
|
||||
else if (caseSensitive && search[ind] != data[index+ind])
|
||||
match = false;
|
||||
}
|
||||
if (match && ind == search.length && search.length > 1)
|
||||
|
||||
59
src/com/projectswg/packets/Searcher.java
Normal file
59
src/com/projectswg/packets/Searcher.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package com.projectswg.packets;
|
||||
|
||||
public abstract class Searcher {
|
||||
|
||||
public int searchForward(int start, String search) {
|
||||
return searchForward(start, search, true);
|
||||
}
|
||||
|
||||
public int searchForward(int start, String search, boolean wrap) {
|
||||
int res = search(start, getSize(), search);
|
||||
if (res != -1 || !wrap)
|
||||
return res;
|
||||
return search(0, start, search);
|
||||
}
|
||||
|
||||
public int searchBackward(int start, String search) {
|
||||
return searchBackward(start, search, true);
|
||||
}
|
||||
|
||||
public int searchBackward(int start, String search, boolean wrap) {
|
||||
int res = search(start, 0, search);
|
||||
if (res != -1 || !wrap)
|
||||
return res;
|
||||
return search(0, start, search);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches from [start, end). Which includes the starting index, but not
|
||||
* the ending index.
|
||||
* @param start the starting index
|
||||
* @param end the ending index
|
||||
* @return the index that the item was found
|
||||
*/
|
||||
public int search(int start, int end, String search) {
|
||||
return search(start, end, end > start, search);
|
||||
}
|
||||
|
||||
private int search(int start, int end, boolean forward, String search) {
|
||||
int inc = forward ? 1 : -1;
|
||||
int index = start;
|
||||
initializeSearch(search);
|
||||
int size = getSize();
|
||||
while ((forward && start < end) || (!forward && start > end)) {
|
||||
if (index < 0 || index >= size)
|
||||
break;
|
||||
if (isMatch(index, search))
|
||||
return index;
|
||||
index += inc;
|
||||
}
|
||||
terminateSearch();
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected abstract int getSize();
|
||||
protected abstract void initializeSearch(String search);
|
||||
protected abstract void terminateSearch();
|
||||
protected abstract boolean isMatch(int index, String search);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user