mirror of
https://github.com/ProjectSWGCore/forwarder.git
synced 2026-07-13 21:01:11 -04:00
236 lines
5.8 KiB
Java
236 lines
5.8 KiB
Java
package com.projectswg;
|
|
|
|
import java.net.BindException;
|
|
import java.net.InetAddress;
|
|
import java.net.SocketException;
|
|
import java.util.Arrays;
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
import network.packets.swg.SWGPacket;
|
|
|
|
import com.projectswg.control.Intent;
|
|
import com.projectswg.control.Service;
|
|
import com.projectswg.intents.ClientConnectionChangedIntent;
|
|
import com.projectswg.intents.ClientSonyPacketIntent;
|
|
import com.projectswg.intents.ServerToClientPacketIntent;
|
|
import com.projectswg.networking.NetInterceptor;
|
|
import com.projectswg.networking.Packet;
|
|
import com.projectswg.networking.UDPServer;
|
|
import com.projectswg.networking.UDPServer.UDPCallback;
|
|
import com.projectswg.networking.sender.PacketPackager;
|
|
import com.projectswg.networking.sender.PacketResender;
|
|
import com.projectswg.networking.soe.Acknowledge;
|
|
import com.projectswg.networking.soe.Disconnect;
|
|
import com.projectswg.networking.soe.OutOfOrder;
|
|
import com.projectswg.networking.soe.SequencedPacket;
|
|
import com.projectswg.networking.soe.Disconnect.DisconnectReason;
|
|
import com.projectswg.utilities.Log;
|
|
|
|
public class ClientSender extends Service {
|
|
|
|
private static final InetAddress ADDR = InetAddress.getLoopbackAddress();
|
|
|
|
private final AtomicBoolean serverRunning;
|
|
private final PacketPackager packager;
|
|
private final PacketResender resender;
|
|
private UDPServer loginServer;
|
|
private UDPServer zoneServer;
|
|
private int connectionId;
|
|
private int port;
|
|
private int loginPort;
|
|
private boolean zone;
|
|
|
|
public ClientSender(NetInterceptor interceptor, int loginPort) {
|
|
this.serverRunning = new AtomicBoolean(false);
|
|
this.packager = new PacketPackager(interceptor, (p) -> send(p));
|
|
this.resender = new PacketResender((data) -> sendRaw(data));
|
|
this.loginPort = loginPort;
|
|
connectionId = -1;
|
|
port = 0;
|
|
zone = false;
|
|
}
|
|
|
|
public boolean initialize() {
|
|
registerForIntent(ClientConnectionChangedIntent.TYPE);
|
|
registerForIntent(ServerToClientPacketIntent.TYPE);
|
|
registerForIntent(ClientSonyPacketIntent.TYPE);
|
|
connectionId = -1;
|
|
port = 0;
|
|
zone = false;
|
|
return super.initialize();
|
|
}
|
|
|
|
public boolean start() {
|
|
reset();
|
|
port = 0;
|
|
zone = false;
|
|
serverRunning.set(false);
|
|
try {
|
|
loginServer = new UDPServer(loginPort, 496);
|
|
zoneServer = new UDPServer(0, 496);
|
|
loginPort = loginServer.getPort();
|
|
packager.start();
|
|
resender.start();
|
|
serverRunning.set(true);
|
|
} catch (BindException e) {
|
|
Log.err(this, "Failed to bind UDP servers! Login Port: " + loginPort);
|
|
return false;
|
|
} catch (SocketException e) {
|
|
Log.err(this, e);
|
|
return false;
|
|
}
|
|
return super.start();
|
|
}
|
|
|
|
public boolean stop() {
|
|
packager.stop();
|
|
resender.stop();
|
|
reset();
|
|
if (loginServer != null)
|
|
loginServer.setCallback(null);
|
|
if (zoneServer != null)
|
|
zoneServer.setCallback(null);
|
|
disconnect(DisconnectReason.APPLICATION);
|
|
serverRunning.set(false);
|
|
safeCloseServers();
|
|
return super.stop();
|
|
}
|
|
|
|
@Override
|
|
public void onIntentReceived(Intent i) {
|
|
if (i instanceof ServerToClientPacketIntent) {
|
|
send(((ServerToClientPacketIntent) i).getRawData());
|
|
} else if (i instanceof ClientSonyPacketIntent) {
|
|
Packet p = ((ClientSonyPacketIntent) i).getPacket();
|
|
if (p instanceof Acknowledge)
|
|
onAcknowledge(((Acknowledge) p).getSequence());
|
|
else if (p instanceof OutOfOrder)
|
|
onOutOfOrder(((OutOfOrder) p).getSequence());
|
|
}
|
|
}
|
|
|
|
public void setLoginCallback(UDPCallback callback) {
|
|
if (loginServer != null)
|
|
loginServer.setCallback(callback);
|
|
}
|
|
|
|
public void setZoneCallback(UDPCallback callback) {
|
|
if (zoneServer != null)
|
|
zoneServer.setCallback(callback);
|
|
}
|
|
|
|
public void setLoginPort(int loginPort) {
|
|
this.loginPort = loginPort;
|
|
}
|
|
|
|
public int getLoginPort() {
|
|
return loginPort;
|
|
}
|
|
|
|
public int getZonePort() {
|
|
if (zoneServer == null)
|
|
return -1;
|
|
return zoneServer.getPort();
|
|
}
|
|
|
|
public int getSequence() {
|
|
return packager.getSequence();
|
|
}
|
|
|
|
public int getConnectionId() {
|
|
return connectionId;
|
|
}
|
|
|
|
public boolean isRunning() {
|
|
return serverRunning.get();
|
|
}
|
|
|
|
public void setZone(boolean zone) {
|
|
this.zone = zone;
|
|
}
|
|
|
|
public void setPort(int port) {
|
|
this.port = port;
|
|
}
|
|
|
|
public void setConnectionId(int connectionId) {
|
|
this.connectionId = connectionId;
|
|
}
|
|
|
|
public void disconnect(DisconnectReason reason) {
|
|
if (connectionId != -1)
|
|
send(new Disconnect(connectionId, reason));
|
|
connectionId = -1;
|
|
}
|
|
|
|
public void reset() {
|
|
packager.reset();
|
|
resender.reset();
|
|
connectionId = -1;
|
|
}
|
|
|
|
public void onOutOfOrder(short sequence) {
|
|
resender.resendTo(sequence);
|
|
}
|
|
|
|
public void onAcknowledge(short sequence) {
|
|
resender.clearTo(sequence);
|
|
}
|
|
|
|
public void send(SWGPacket ... packets) {
|
|
for (SWGPacket packet : packets) {
|
|
send(packet.encode().array());
|
|
}
|
|
}
|
|
|
|
public void send(byte [] data) {
|
|
packager.addToPackage(data);
|
|
}
|
|
|
|
public void sendRaw(byte [] data) {
|
|
sendRaw(port, data);
|
|
}
|
|
|
|
public void sendRaw(int port, byte [] data) {
|
|
if (port == 0) {
|
|
Log.err(this, "Cannot send to port 0! Data: " + Arrays.toString(data));
|
|
return;
|
|
}
|
|
if (zone && zoneServer != null)
|
|
zoneServer.send(port, ADDR, data);
|
|
else if (!zone && loginServer != null)
|
|
loginServer.send(port, ADDR, data);
|
|
else {
|
|
Log.err(this, "No matching server! isZone=%b: Login=%b Zone=%b", zone, loginServer!=null, zoneServer!=null);
|
|
return;
|
|
}
|
|
}
|
|
|
|
public void send(Packet packet) {
|
|
if (port == 0)
|
|
return;
|
|
byte [] data = packet.encode().array();
|
|
if (packet instanceof SequencedPacket) {
|
|
resender.add(((SequencedPacket) packet).getSequence(), data);
|
|
} else {
|
|
sendRaw(data);
|
|
}
|
|
}
|
|
|
|
private void safeCloseServers() {
|
|
if (loginServer != null) {
|
|
loginServer.close();
|
|
loginServer = null;
|
|
}
|
|
if (zoneServer != null) {
|
|
zoneServer.close();
|
|
zoneServer = null;
|
|
}
|
|
}
|
|
|
|
public interface ClientSenderCallback {
|
|
void onUdpSent(boolean zone, byte [] data);
|
|
}
|
|
|
|
}
|