From 880eb378177794c89df4955acad3d3a23e6dfc01 Mon Sep 17 00:00:00 2001 From: rtm516 Date: Mon, 19 Aug 2024 15:59:00 +0100 Subject: [PATCH] Fix SDP session Id and DTLS --- .../bootstrap/standalone/StandaloneMain.java | 7 +- core/build.gradle.kts | 12 ++- .../core/webrtc/CustomDatagramTransport.java | 48 +++++++++++ .../core/webrtc/RtcWebsocketClient.java | 81 ++++++++----------- 4 files changed, 90 insertions(+), 58 deletions(-) create mode 100644 core/src/main/java/com/rtm516/mcxboxbroadcast/core/webrtc/CustomDatagramTransport.java diff --git a/bootstrap/standalone/src/main/java/com/rtm516/mcxboxbroadcast/bootstrap/standalone/StandaloneMain.java b/bootstrap/standalone/src/main/java/com/rtm516/mcxboxbroadcast/bootstrap/standalone/StandaloneMain.java index 563040d..2fc1e9c 100644 --- a/bootstrap/standalone/src/main/java/com/rtm516/mcxboxbroadcast/bootstrap/standalone/StandaloneMain.java +++ b/bootstrap/standalone/src/main/java/com/rtm516/mcxboxbroadcast/bootstrap/standalone/StandaloneMain.java @@ -11,6 +11,8 @@ import com.rtm516.mcxboxbroadcast.core.exceptions.SessionCreationException; import com.rtm516.mcxboxbroadcast.core.exceptions.SessionUpdateException; import com.rtm516.mcxboxbroadcast.core.storage.FileStorageManager; +import org.slf4j.LoggerFactory; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -18,7 +20,6 @@ import java.net.InetSocketAddress; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import org.slf4j.LoggerFactory; public class StandaloneMain { private static StandaloneConfig config; @@ -28,10 +29,6 @@ public class StandaloneMain { public static SessionManager sessionManager; public static void main(String[] args) throws Exception { - main0(); - } - - private static void main0() throws Exception { logger = new StandaloneLoggerImpl(LoggerFactory.getLogger(StandaloneMain.class)); logger.info("Starting MCXboxBroadcast Standalone " + BuildData.VERSION); diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 31d065e..4686b09 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -10,10 +10,6 @@ dependencies { api(libs.methanol) api(libs.minecraftauth) - api("org.jitsi:ice4j:3.0-72-g824cd4b") - api("org.bouncycastle:bctls-jdk18on:1.78.1") -// implementation("org.bouncycastle:bctls-debug-jdk18on:1.78.1") - implementation("dev.onvoid.webrtc:webrtc-java:0.8.0") implementation("dev.onvoid.webrtc", "webrtc-java", "0.8.0", classifier = "windows-x86_64") implementation("dev.onvoid.webrtc", "webrtc-java", "0.8.0", classifier = "macos-x86_64") @@ -21,6 +17,14 @@ dependencies { implementation("dev.onvoid.webrtc", "webrtc-java", "0.8.0", classifier = "linux-x86_64") implementation("dev.onvoid.webrtc", "webrtc-java", "0.8.0", classifier = "linux-aarch64") implementation("dev.onvoid.webrtc", "webrtc-java", "0.8.0", classifier = "linux-aarch32") + + api("org.jitsi:ice4j:3.0-72-g824cd4b") + api("org.bouncycastle:bcprov-jdk18on:1.78.1") + api("org.bouncycastle:bctls-jdk18on:1.78.1") + api("org.bouncycastle:bcpkix-jdk18on:1.78.1") + + // For sctp4j + implementation(files("libs/sctp4j-1.0.6.jar")) } sourceSets { diff --git a/core/src/main/java/com/rtm516/mcxboxbroadcast/core/webrtc/CustomDatagramTransport.java b/core/src/main/java/com/rtm516/mcxboxbroadcast/core/webrtc/CustomDatagramTransport.java new file mode 100644 index 0000000..c7a3069 --- /dev/null +++ b/core/src/main/java/com/rtm516/mcxboxbroadcast/core/webrtc/CustomDatagramTransport.java @@ -0,0 +1,48 @@ +package com.rtm516.mcxboxbroadcast.core.webrtc; + +import org.bouncycastle.tls.DatagramTransport; +import org.ice4j.ice.Component; +import org.ice4j.ice.ComponentSocket; + +import java.io.IOException; +import java.net.DatagramPacket; + +public class CustomDatagramTransport implements DatagramTransport { + private final ComponentSocket socket; + private final Component component; + private final int receiveLimit = 1500; // Typically, a standard MTU size + private final int sendLimit = 1500; // Typically, a standard MTU size + + public CustomDatagramTransport(Component component) { + this.socket = component.getComponentSocket(); + this.component = component; + } + + @Override + public int getReceiveLimit() { + return receiveLimit; + } + + @Override + public int getSendLimit() { + return sendLimit; + } + + @Override + public int receive(byte[] buf, int off, int len, int waitMillis) throws IOException { + DatagramPacket packet = new DatagramPacket(buf, off, len); + socket.receive(packet); + return packet.getLength(); + } + + @Override + public void send(byte[] buf, int off, int len) throws IOException { + DatagramPacket packet = new DatagramPacket(buf, off, len, component.getDefaultCandidate().getTransportAddress()); + socket.send(packet); + } + + @Override + public void close() throws IOException { + socket.close(); + } +} diff --git a/core/src/main/java/com/rtm516/mcxboxbroadcast/core/webrtc/RtcWebsocketClient.java b/core/src/main/java/com/rtm516/mcxboxbroadcast/core/webrtc/RtcWebsocketClient.java index 8e0326a..7a7f72f 100644 --- a/core/src/main/java/com/rtm516/mcxboxbroadcast/core/webrtc/RtcWebsocketClient.java +++ b/core/src/main/java/com/rtm516/mcxboxbroadcast/core/webrtc/RtcWebsocketClient.java @@ -9,28 +9,14 @@ import com.rtm516.mcxboxbroadcast.core.models.ws.WsToMessage; import dev.onvoid.webrtc.PeerConnectionFactory; import dev.onvoid.webrtc.RTCConfiguration; -import dev.onvoid.webrtc.RTCIceServer; -import gov.nist.javax.sdp.SdpEncoderImpl; -import gov.nist.javax.sdp.fields.MediaField; -import gov.nist.javax.sdp.parser.ConnectionFieldParser; -import gov.nist.javax.sdp.parser.MediaFieldParser; -import gov.nist.javax.sdp.parser.SDPAnnounceParser; import io.jsonwebtoken.lang.Collections; -import java.io.FileInputStream; -import java.io.FileNotFoundException; + import java.io.IOException; import java.math.BigInteger; import java.net.URI; import java.security.KeyPairGenerator; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.Security; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.spec.RSAKeyGenParameterSpec; -import java.text.ParseException; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -39,49 +25,30 @@ import java.util.Vector; import javax.sdp.Attribute; import javax.sdp.MediaDescription; -import javax.sdp.SdpEncoder; -import javax.sdp.SdpException; -import javax.sdp.SdpFactory; + import org.bouncycastle.asn1.x509.X509Name; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.tls.AlertDescription; -import org.bouncycastle.tls.Certificate; import org.bouncycastle.tls.CertificateRequest; import org.bouncycastle.tls.DTLSClientProtocol; import org.bouncycastle.tls.DefaultTlsClient; -import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.ProtocolVersion; import org.bouncycastle.tls.TlsAuthentication; -import org.bouncycastle.tls.TlsCredentialedSigner; import org.bouncycastle.tls.TlsCredentials; import org.bouncycastle.tls.TlsFatalAlert; -import org.bouncycastle.tls.TlsPeer; import org.bouncycastle.tls.TlsServerCertificate; -import org.bouncycastle.tls.crypto.TlsCryptoParameters; -import org.bouncycastle.tls.crypto.TlsCryptoProvider; -import org.bouncycastle.tls.crypto.TlsCryptoUtils; -import org.bouncycastle.tls.crypto.TlsStreamSigner; -import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; -import org.bouncycastle.tls.crypto.impl.jcajce.JcaDefaultTlsCredentialedSigner; -import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto; import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider; -import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedAgreement; -import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedDecryptor; -import org.bouncycastle.x509.X509CertificatePair; import org.bouncycastle.x509.X509V3CertificateGenerator; import org.ice4j.Transport; import org.ice4j.TransportAddress; -import org.ice4j.attribute.AttributeFactory; import org.ice4j.ice.Agent; -import org.ice4j.ice.harvest.HarvestConfig; -import org.ice4j.ice.harvest.StunCandidateHarvest; +import org.ice4j.ice.Component; +import org.ice4j.ice.IceMediaStream; import org.ice4j.ice.harvest.StunCandidateHarvester; -import org.ice4j.ice.harvest.StunMappingCandidateHarvester; import org.ice4j.ice.harvest.TurnCandidateHarvester; -import org.ice4j.ice.sdp.IceSdpUtils; import org.ice4j.security.LongTermCredential; import org.java_websocket.client.WebSocketClient; import org.java_websocket.handshake.ServerHandshake; -import org.jitsi.config.JitsiConfig; import org.opentelecoms.javax.sdp.NistSdpFactory; /** @@ -119,9 +86,9 @@ public RtcWebsocketClient(String authenticationToken, ExpandedSessionInfo sessio /** * When the web socket connects send the request for the connection ID - * + * * @see WebSocketClient#onOpen(ServerHandshake) - * + * * @param serverHandshake The handshake of the websocket instance */ @Override @@ -131,9 +98,9 @@ public void onOpen(ServerHandshake serverHandshake) { /** * When we get a message check if it's a connection ID message * and handle otherwise ignore it - * - * @see WebSocketClient#onMessage(String) - * + * + * @see WebSocketClient#onMessage(String) + * * @param data The UTF-8 decoded message that was received. */ @Override @@ -231,12 +198,24 @@ public TlsCredentials getClientCredentials(CertificateRequest certificateRequest } }; } + + @Override + protected ProtocolVersion[] getSupportedVersions() { + return new ProtocolVersion[]{ProtocolVersion.DTLSv12}; + } }; -// new DTLSClientProtocol().connect(client); + IceMediaStream stream = agent.createMediaStream("data"); + Component component = agent.createComponent(stream, 5000, 5000, 6000); + + CustomDatagramTransport datagramTransport = new CustomDatagramTransport(component); var answer = factory.createSessionDescription(); - answer.setOrigin(factory.createOrigin("-", new Random().nextLong(), 2L, "IN", "IP4", "127.0.0.1")); + long answerSessionId = new Random().nextLong(); + while (answerSessionId < 0) { + answerSessionId = new Random().nextLong(); + } + answer.setOrigin(factory.createOrigin("-", answerSessionId, 2L, "IN", "IP4", "127.0.0.1")); var attributes = new Vector<>(); attributes.add(factory.createAttribute("group", "BUNDLE 0")); @@ -252,10 +231,14 @@ public TlsCredentials getClientCredentials(CertificateRequest certificateRequest answer.setMediaDescriptions(new Vector<>(Collections.of(media))); var json = Constants.GSON.toJson(new WsToMessage( - 1, from, "CONNECTRESPONSE " + sessionId + " " + answer + 1, from, "CONNECTRESPONSE " + answerSessionId + " " + answer )); System.out.println(json); send(json); + + // Move this since it errors since the socket isnt open, I assume bc we havent sent the CANDIDATEADD responses + new DTLSClientProtocol().connect(client, datagramTransport); + // } catch (SdpException | FileNotFoundException | CertificateException | NoSuchAlgorithmException e) { } catch (Exception e) { throw new RuntimeException(e); @@ -306,8 +289,8 @@ private void initialize(JsonObject message) { yield new StunCandidateHarvester(new TransportAddress(host, port, Transport.UDP)); case "turn": yield new TurnCandidateHarvester( - new TransportAddress(host, port, Transport.UDP), - new LongTermCredential(username, password) + new TransportAddress(host, port, Transport.UDP), + new LongTermCredential(username, password) ); default: throw new IllegalStateException("Unexpected value: " + type); @@ -329,4 +312,4 @@ public void onError(Exception ex) { // protected PeerConnectionFactory peerFactory() { // return peerFactory; // } -} +} \ No newline at end of file