Updated the TCP Handshake to also negotiate a protocol version. +Formatting etc.

This commit is contained in:
Maschell 2017-04-10 15:43:54 +02:00
parent 857c5d397d
commit 8197db4d86
9 changed files with 137 additions and 33 deletions

View File

@ -41,8 +41,6 @@ import lombok.Getter;
import net.ash.HIDToVPADNetworkClient.manager.ControllerManager; import net.ash.HIDToVPADNetworkClient.manager.ControllerManager;
import net.ash.HIDToVPADNetworkClient.network.NetworkManager; import net.ash.HIDToVPADNetworkClient.network.NetworkManager;
import net.ash.HIDToVPADNetworkClient.util.Settings; import net.ash.HIDToVPADNetworkClient.util.Settings;
import java.awt.BorderLayout;
import java.awt.CardLayout;
public final class GuiInputControls extends JPanel { public final class GuiInputControls extends JPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -132,7 +130,6 @@ public final class GuiInputControls extends JPanel {
add(Box.createRigidArea(new Dimension(1, 4))); add(Box.createRigidArea(new Dimension(1, 4)));
add(autoActivateWrap); add(autoActivateWrap);
add(Box.createVerticalGlue()); add(Box.createVerticalGlue());
add(Box.createVerticalGlue()); add(Box.createVerticalGlue());

View File

@ -25,42 +25,47 @@ package net.ash.HIDToVPADNetworkClient.hid;
public interface HidDevice { public interface HidDevice {
/** /**
* Opens the HidDevice for usage. * Opens the HidDevice for usage.
*
* @return true on success, false when it failed. * @return true on success, false when it failed.
*/ */
boolean open(); boolean open();
/** /**
* Closes the HidDevice * Closes the HidDevice
*/ */
void close(); void close();
/** /**
* Returns the VendorID of the HidDevice * Returns the VendorID of the HidDevice
*
* @return vendorID * @return vendorID
*/ */
short getVendorId(); short getVendorId();
/** /**
* Returns the ProductID of the HidDevice * Returns the ProductID of the HidDevice
*
* @return productID * @return productID
*/ */
short getProductId(); short getProductId();
/** /**
* Returns the latest data. * Returns the latest data.
*
* @return An byte array containing the latest data. If no data is present, it'll return a empty byte array * @return An byte array containing the latest data. If no data is present, it'll return a empty byte array
*/ */
byte[] getLatestData(); byte[] getLatestData();
/** /**
* Retuns the Usage of this HID-Device * Retuns the Usage of this HID-Device
*
* @return usage * @return usage
*/ */
short getUsage(); short getUsage();
/** /**
* Returns the path of this HidDevice * Returns the path of this HidDevice
*
* @return path * @return path
*/ */
String getPath(); String getPath();

View File

@ -37,12 +37,13 @@ public class HidManager {
public static HidDevice getDeviceByPath(String path) throws IOException { public static HidDevice getDeviceByPath(String path) throws IOException {
return backend.getDeviceByPath(path); return backend.getDeviceByPath(path);
} }
public static List<HidDevice> getAttachedControllers() { public static List<HidDevice> getAttachedControllers() {
List<HidDevice> connectedGamepads = new ArrayList<HidDevice>(); List<HidDevice> connectedGamepads = new ArrayList<HidDevice>();
for (HidDevice info : backend.enumerateDevices()) { for (HidDevice info : backend.enumerateDevices()) {
if (isGamepad(info)) { if (isGamepad(info)) {
// Skip Xbox controller under windows. We should use XInput instead. // Skip Xbox controller under windows. We should use XInput instead.
if (isXboxController(info) && Settings.isWindows()) { if (isXboxController(info) && Settings.isWindows()) {
continue; continue;
@ -61,17 +62,17 @@ public class HidManager {
private static boolean isPlaystationController(HidDevice info) { private static boolean isPlaystationController(HidDevice info) {
if (info == null) return false; if (info == null) return false;
return (info.getVendorId() == 0x054c); return (info.getVendorId() == (short) 0x054c);
} }
private static boolean isNintendoController(HidDevice info) { private static boolean isNintendoController(HidDevice info) {
if (info == null) return false; if (info == null) return false;
return (info.getVendorId() == 0x57e); return (info.getVendorId() == (short) 0x57e);
} }
private static boolean isXboxController(HidDevice info) { private static boolean isXboxController(HidDevice info) {
if (info == null) return false; if (info == null) return false;
return (info.getVendorId() == 0x045e) && ((info.getProductId() == 0x02ff) || (info.getProductId() == 0x02a1)); return (info.getVendorId() == (short) 0x045e) && ((info.getProductId() == (short) 0x02ff) || (info.getProductId() == (short) 0x02a1));
} }
static { static {
@ -81,13 +82,13 @@ public class HidManager {
backend = new PureJavaHidManagerBackend(); backend = new PureJavaHidManagerBackend();
} else if (Settings.isLinux()) { } else if (Settings.isLinux()) {
backend = new Hid4JavaHidManagerBackend(); backend = new Hid4JavaHidManagerBackend();
} else{ } else {
backend = null; backend = null;
} }
log.info("Plattform: " + System.getProperty("os.name")); log.info("Plattform: " + System.getProperty("os.name"));
if(backend != null){ if (backend != null) {
log.info("Backend: " + backend.getClass().getSimpleName()); log.info("Backend: " + backend.getClass().getSimpleName());
}else{ } else {
log.info("No Backend loaded =("); log.info("No Backend loaded =(");
} }
} }

View File

@ -68,7 +68,7 @@ class Hid4JavaHidDevice implements HidDevice {
@Override @Override
public String toString() { public String toString() {
return "Hid4JavaHidDevice [myDevice=" + myDevice + ", data=" + Arrays.toString(data) + "]"; return "Hid4JavaHidDevice [vid= " + getVendorId() + ", pid= " + getProductId() + ", data=" + Arrays.toString(data) + "]";
} }
@Override @Override

View File

@ -89,4 +89,10 @@ class PureJavaHidDevice implements HidDevice, InputReportListener {
public String getPath() { public String getPath() {
return myDeviceInfo.getPath(); return myDeviceInfo.getPath();
} }
@Override
public String toString() {
return "PureJavaHidDevice [vid= " + String.format("%04X", getVendorId()) + ", pid= " + String.format("%04X", getProductId()) + ", path= " + getPath()
+ ", data=" + Arrays.toString(currentData) + "]";
}
} }

View File

@ -31,6 +31,7 @@ import lombok.Synchronized;
import lombok.extern.java.Log; import lombok.extern.java.Log;
import net.ash.HIDToVPADNetworkClient.controller.Controller; import net.ash.HIDToVPADNetworkClient.controller.Controller;
import net.ash.HIDToVPADNetworkClient.manager.ActiveControllerManager; import net.ash.HIDToVPADNetworkClient.manager.ActiveControllerManager;
import net.ash.HIDToVPADNetworkClient.network.Protocol.HandshakeReturnCode;
import net.ash.HIDToVPADNetworkClient.util.MessageBox; import net.ash.HIDToVPADNetworkClient.util.MessageBox;
import net.ash.HIDToVPADNetworkClient.util.MessageBoxManager; import net.ash.HIDToVPADNetworkClient.util.MessageBoxManager;
import net.ash.HIDToVPADNetworkClient.util.Settings; import net.ash.HIDToVPADNetworkClient.util.Settings;
@ -163,7 +164,7 @@ public final class NetworkManager implements Runnable {
try { try {
pong = tcpClient.recvByte(); pong = tcpClient.recvByte();
if (pong == Protocol.TCP_CMD_PONG) { if (pong == Protocol.TCP_CMD_PONG) {
log.info("Ping...Pong!"); if (Settings.DEBUG_TCP_PING_PONG) log.info("Ping...Pong!");
} else { } else {
log.info("Got no valid response to a Ping. Disconnecting."); log.info("Got no valid response to a Ping. Disconnecting.");
disconnect(); disconnect();
@ -344,13 +345,18 @@ public final class NetworkManager implements Runnable {
boolean result = false; boolean result = false;
log.info("Trying to connect to: " + ip); log.info("Trying to connect to: " + ip);
try { try {
tcpClient.connect(ip); HandshakeReturnCode tcpresult = tcpClient.connect(ip);
log.info("TCP Connected!"); if (tcpresult == HandshakeReturnCode.GOOD_HANDSHAKE) {
udpClient = UDPClient.createUDPClient(ip); log.info("TCP Connected!");
if (udpClient != null) { udpClient = UDPClient.createUDPClient(ip);
result = true; if (udpClient != null) {
result = true;
}
} else {
String error = "Error while connecting.";
log.info(error);
} }
} catch (Exception e) { } catch (IOException e) {
String error = "Error while connecting: " + e.getMessage(); String error = "Error while connecting: " + e.getMessage();
log.info(error); log.info(error);
MessageBoxManager.addMessageBox(error, MessageBox.MESSAGE_WARNING); MessageBoxManager.addMessageBox(error, MessageBox.MESSAGE_WARNING);

View File

@ -28,13 +28,22 @@ import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
import lombok.extern.java.Log; import lombok.extern.java.Log;
import net.ash.HIDToVPADNetworkClient.manager.ActiveControllerManager;
import net.ash.HIDToVPADNetworkClient.util.MessageBox;
import net.ash.HIDToVPADNetworkClient.util.MessageBoxManager;
@Log @Log
final class Protocol { final class Protocol {
private static ProtocolVersion currentProtocol = ProtocolVersion.MY_VERSION;
static final int TCP_PORT = 8112; static final int TCP_PORT = 8112;
static final int UDP_PORT = 8113; static final int UDP_PORT = 8113;
static final byte TCP_HANDSHAKE = 0x12; static final byte TCP_HANDSHAKE_VERSION_1 = 0x12;
static final byte TCP_HANDSHAKE_VERSION_2 = 0x13;
static final byte TCP_HANDSHAKE_ABORT = 0x30;
static final byte TCP_HANDSHAKE = TCP_HANDSHAKE_VERSION_2; // default version.
static final byte TCP_SAME_CLIENT = 0x20; static final byte TCP_SAME_CLIENT = 0x20;
static final byte TCP_NEW_CLIENT = 0x21; static final byte TCP_NEW_CLIENT = 0x21;
@ -96,4 +105,85 @@ final class Protocol {
return bos.toByteArray(); return bos.toByteArray();
} }
public static HandshakeReturnCode doHandshake(TCPClient tcpClient) throws IOException {
Protocol.currentProtocol = ProtocolVersion.MY_VERSION;
HandshakeReturnCode resultHandshake = HandshakeReturnCode.BAD_HANDSHAKE;
ProtocolVersion wiiuProtocolVersion = ProtocolVersion.getEnumByValue(tcpClient.recvByte());
/**
* Handshake 1. At first the server (WiiU) sends his protocol version 2. The network clients answers with his preferred version (which needs to be
* equals or lower the version the server (WiiU) sent him) or an abort command. 3a. If the client sent a abort, close the connection and wait for
* another connection 3b. If the client sent his highest supported version, the server confirm that he is able to use this version (by sending the
* version back) or sending a abort command to disconnect.
**/
if (wiiuProtocolVersion == ProtocolVersion.UNKOWN) {
log.info("Connected to a WiiU with an unsupported protocol version. It may support an older though");
tcpClient.send(ProtocolVersion.MY_VERSION.getVersionByte());
} else if (wiiuProtocolVersion == ProtocolVersion.Version1) {
// Do nothing.
} else if (wiiuProtocolVersion == ProtocolVersion.Version2) {
// We want to do version 2!
tcpClient.send(ProtocolVersion.Version2.getVersionByte());
}
if (wiiuProtocolVersion == ProtocolVersion.Version1) {
Protocol.currentProtocol = ProtocolVersion.Version1;
resultHandshake = HandshakeReturnCode.GOOD_HANDSHAKE;
} else {
ProtocolVersion finalProtocolVersion = ProtocolVersion.getEnumByValue(tcpClient.recvByte());
if (finalProtocolVersion == ProtocolVersion.Abort) {
String message = "The HIDtoVPAD version is not supported. Try to use the newest version of HIDtoVPAD and this network client.";
log.info(message);
MessageBoxManager.addMessageBox(message, MessageBox.MESSAGE_ERROR);
resultHandshake = HandshakeReturnCode.BAD_HANDSHAKE;
} else if (finalProtocolVersion == ProtocolVersion.UNKOWN) {
String message = "Something stranged happend while connecting. Try to use the newest version of HIDtoVPAD and this network client.";
log.info(message);
MessageBoxManager.addMessageBox(message, MessageBox.MESSAGE_ERROR);
resultHandshake = HandshakeReturnCode.BAD_HANDSHAKE;
} else {
Protocol.currentProtocol = finalProtocolVersion;
resultHandshake = HandshakeReturnCode.GOOD_HANDSHAKE;
}
}
if (resultHandshake == HandshakeReturnCode.GOOD_HANDSHAKE) {
ActiveControllerManager.getInstance().attachAllActiveControllers();
log.info("Handshake was successful! Using protocol version " + (currentProtocol.getVersionByte() - TCP_HANDSHAKE_VERSION_1 + 1));
return resultHandshake;
} else {
log.info("[TCP] Handshaking failed");
return resultHandshake;
}
// return false;
}
public enum ProtocolVersion {
MY_VERSION((byte) TCP_HANDSHAKE), Version1((byte) TCP_HANDSHAKE_VERSION_1), Version2((byte) TCP_HANDSHAKE_VERSION_2), Abort(
(byte) TCP_HANDSHAKE_ABORT), UNKOWN((byte) 0x00);
private final byte versionByte;
private ProtocolVersion(byte versionByte) {
this.versionByte = versionByte;
}
public static ProtocolVersion getEnumByValue(byte value) {
switch (value) {
case TCP_HANDSHAKE_VERSION_1:
return ProtocolVersion.Version1;
case TCP_HANDSHAKE_VERSION_2:
return ProtocolVersion.Version2;
case TCP_HANDSHAKE_ABORT:
return ProtocolVersion.Abort;
default:
return ProtocolVersion.UNKOWN;
}
}
public byte getVersionByte() {
return versionByte;
}
}
} }

View File

@ -33,7 +33,6 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.Synchronized; import lombok.Synchronized;
import lombok.extern.java.Log; import lombok.extern.java.Log;
import net.ash.HIDToVPADNetworkClient.manager.ActiveControllerManager;
import net.ash.HIDToVPADNetworkClient.network.Protocol.HandshakeReturnCode; import net.ash.HIDToVPADNetworkClient.network.Protocol.HandshakeReturnCode;
import net.ash.HIDToVPADNetworkClient.util.Settings; import net.ash.HIDToVPADNetworkClient.util.Settings;
@ -53,23 +52,18 @@ final class TCPClient {
} }
@Synchronized("lock") @Synchronized("lock")
void connect(String ip) throws Exception { HandshakeReturnCode connect(String ip) throws IOException {
sock = new Socket(); sock = new Socket();
sock.connect(new InetSocketAddress(ip, Protocol.TCP_PORT), 2000); sock.connect(new InetSocketAddress(ip, Protocol.TCP_PORT), 2000);
in = new DataInputStream(sock.getInputStream()); in = new DataInputStream(sock.getInputStream());
out = new DataOutputStream(sock.getOutputStream()); out = new DataOutputStream(sock.getOutputStream());
HandshakeReturnCode resultHandshake = HandshakeReturnCode.GOOD_HANDSHAKE; HandshakeReturnCode result = Protocol.doHandshake(this);
if (recvByte() != Protocol.TCP_HANDSHAKE) resultHandshake = HandshakeReturnCode.BAD_HANDSHAKE; if (result == HandshakeReturnCode.GOOD_HANDSHAKE) {
if (resultHandshake == HandshakeReturnCode.GOOD_HANDSHAKE) {
ActiveControllerManager.getInstance().attachAllActiveControllers();
this.ip = ip; this.ip = ip;
shouldRetry = 0; shouldRetry = 0;
} else {
log.info("[TCP] Handshaking failed");
throw new Exception();
} }
return result;
} }
@Synchronized("lock") @Synchronized("lock")
@ -112,6 +106,10 @@ final class TCPClient {
send(ByteBuffer.allocate(4).putInt(value).array()); send(ByteBuffer.allocate(4).putInt(value).array());
} }
public void send(byte _byte) throws IOException {
send(ByteBuffer.allocate(1).put(_byte).array());
}
@Synchronized("lock") @Synchronized("lock")
byte recvByte() throws IOException { byte recvByte() throws IOException {
return in.readByte(); return in.readByte();

View File

@ -49,6 +49,7 @@ public final class Settings {
public static boolean SCAN_AUTOMATICALLY_FOR_CONTROLLERS = true; public static boolean SCAN_AUTOMATICALLY_FOR_CONTROLLERS = true;
public static boolean DEBUG_UDP_OUTPUT = false; public static boolean DEBUG_UDP_OUTPUT = false;
public static boolean DEBUG_TCP_PING_PONG = false;
public static boolean SEND_DATA_ONLY_ON_CHANGE = false; public static boolean SEND_DATA_ONLY_ON_CHANGE = false;
public static boolean AUTO_ACTIVATE_CONTROLLER = false; public static boolean AUTO_ACTIVATE_CONTROLLER = false;