From 9a0ce02523a03bb7ef40d2ad1680267fefa84efe Mon Sep 17 00:00:00 2001 From: Nils Sowen Date: Sun, 10 Jul 2022 12:49:00 +0200 Subject: [PATCH 1/4] Allow sending and receiving messages over the same UDP socket --- .../com/illposed/osc/transport/OSCPort.java | 11 ++++++ .../com/illposed/osc/transport/OSCPortIn.java | 22 +++++++++++ .../osc/transport/OSCPortInBuilder.java | 37 ++++++++++++++++-- .../illposed/osc/transport/OSCPortOut.java | 13 +++++++ .../osc/transport/OSCPortOutBuilder.java | 29 ++++++++++++++ .../osc/transport/udp/UDPTransport.java | 4 +- .../illposed/osc/transport/OSCPortTest.java | 38 +++++++++++++++++++ 7 files changed, 149 insertions(+), 5 deletions(-) diff --git a/modules/core/src/main/java/com/illposed/osc/transport/OSCPort.java b/modules/core/src/main/java/com/illposed/osc/transport/OSCPort.java index 7a980d97..0552fa52 100644 --- a/modules/core/src/main/java/com/illposed/osc/transport/OSCPort.java +++ b/modules/core/src/main/java/com/illposed/osc/transport/OSCPort.java @@ -70,6 +70,17 @@ protected OSCPort( this(local, remote, serializerAndParserBuilder, NetworkProtocol.UDP); } + protected OSCPort( + final Transport transport) + { + if (transport == null) { + throw new IllegalStateException( + "Can not use NULL as transport" + ); + } + this.transport = transport; + } + public Transport getTransport() { return transport; } diff --git a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortIn.java b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortIn.java index b18a90da..c247f0c6 100644 --- a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortIn.java +++ b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortIn.java @@ -86,6 +86,28 @@ public static List defaultPacketListeners() { return listeners; } + /** + * Create an OSC-Port that uses a concrete {@code transport} given + * as parameter and with {@link #isResilient() resilient} set to true. + * One must make sure that the appropriate connection + * has already been set up before using this instance, meaning + * that local and remote address are set correctly. + * @param transport the transport used for receiving OSC packets + * @param packetListeners to handle received and serialized OSC packets + * @throws IOException if we fail to bind a channel to the local address + */ + public OSCPortIn( + final Transport transport, + final List packetListeners) + { + super(transport); + + this.listening = false; + this.daemonListener = true; + this.resilient = true; + this.packetListeners = packetListeners; + } + /** * Create an OSC-Port that listens on the given local socket for packets from {@code remote}, * using a parser created with the given factory, diff --git a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortInBuilder.java b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortInBuilder.java index 3486419f..94b27150 100644 --- a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortInBuilder.java +++ b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortInBuilder.java @@ -24,6 +24,7 @@ public class OSCPortInBuilder { private SocketAddress local; private SocketAddress remote; private NetworkProtocol networkProtocol = NetworkProtocol.UDP; + private Transport transport; private OSCPacketListener addDefaultPacketListener() { if (packetListeners == null) { @@ -37,6 +38,33 @@ private OSCPacketListener addDefaultPacketListener() { } public OSCPortIn build() throws IOException { + + if (packetListeners == null) { + addDefaultPacketListener(); + } + + // If transport is set, other settings cannot be used + if (transport != null) { + if (remote != null) { + throw new IllegalArgumentException( + "Cannot use remote socket address / port in conjunction with transport object."); + } + + if (local != null) { + throw new IllegalArgumentException( + "Cannot use local socket address / port in conjunction with transport object."); + } + + if (parserBuilder != null) { + throw new IllegalArgumentException( + "Cannot use parserBuilder in conjunction with transport object."); + } + + return new OSCPortIn( + transport, packetListeners + ); + } + if (local == null) { throw new IllegalArgumentException( "Missing local socket address / port."); @@ -50,10 +78,6 @@ public OSCPortIn build() throws IOException { parserBuilder = new OSCSerializerAndParserBuilder(); } - if (packetListeners == null) { - addDefaultPacketListener(); - } - return new OSCPortIn( parserBuilder, packetListeners, local, remote, networkProtocol ); @@ -97,6 +121,11 @@ public OSCPortInBuilder setNetworkProtocol(final NetworkProtocol protocol) { return this; } + public OSCPortInBuilder setTransport(final Transport networkTransport) { + transport = networkTransport; + return this; + } + public OSCPortInBuilder setPacketListeners( final List listeners) { diff --git a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOut.java b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOut.java index 5e6436b8..51dda36f 100644 --- a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOut.java +++ b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOut.java @@ -108,6 +108,19 @@ public OSCPortOut() throws IOException { this(new InetSocketAddress(InetAddress.getLocalHost(), DEFAULT_SC_OSC_PORT)); } + /** + * Creates an OSC-Port that sends to a remote host from the specified given + * {@code transport} that was previously created using appropriate local + * and remote addresses, network protocol, and serializers. + * @param transport the transport used for sending OSC packets + * @throws IOException if we fail to bind a channel to the local address + */ + public OSCPortOut( + final Transport transport) + { + super(transport); + } + /** * Converts and sends an OSC packet (message or bundle) to the remote address. * @param packet the bundle or message to be converted and sent diff --git a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOutBuilder.java b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOutBuilder.java index 6792b3e2..e90eed8f 100644 --- a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOutBuilder.java +++ b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOutBuilder.java @@ -17,8 +17,32 @@ public class OSCPortOutBuilder { private SocketAddress remote; private SocketAddress local; private NetworkProtocol networkProtocol = NetworkProtocol.UDP; + private Transport transport; public OSCPortOut build() throws IOException { + + // If transport is set, other settings cannot be used + if (transport != null) { + if (remote != null) { + throw new IllegalArgumentException( + "Cannot use remote socket address / port in conjunction with transport."); + } + + if (local != null) { + throw new IllegalArgumentException( + "Cannot use local socket address / port in conjunction with transport."); + } + + if (serializerBuilder != null) { + throw new IllegalArgumentException( + "Cannot use serializerBuilder in conjunction with transport."); + } + + return new OSCPortOut( + transport + ); + } + if (remote == null) { throw new IllegalArgumentException( "Missing remote socket address / port."); @@ -74,4 +98,9 @@ public OSCPortOutBuilder setNetworkProtocol(final NetworkProtocol protocol) { networkProtocol = protocol; return this; } + + public OSCPortOutBuilder setTransport(final Transport networkTransport) { + transport = networkTransport; + return this; + } } diff --git a/modules/core/src/main/java/com/illposed/osc/transport/udp/UDPTransport.java b/modules/core/src/main/java/com/illposed/osc/transport/udp/UDPTransport.java index 46d9d59a..78d3a879 100644 --- a/modules/core/src/main/java/com/illposed/osc/transport/udp/UDPTransport.java +++ b/modules/core/src/main/java/com/illposed/osc/transport/udp/UDPTransport.java @@ -24,7 +24,9 @@ /** * A {@link Transport} implementation for sending and receiving OSC packets over - * a network via UDP. + * a network via UDP. This implementation uses separate ByteBuffers for sending + * and receiving, making it possible to use the same UDP socket for sending packets + * and listening simultaneously. */ public class UDPTransport implements Transport { diff --git a/modules/core/src/test/java/com/illposed/osc/transport/OSCPortTest.java b/modules/core/src/test/java/com/illposed/osc/transport/OSCPortTest.java index 2d94c1e7..41b4600e 100644 --- a/modules/core/src/test/java/com/illposed/osc/transport/OSCPortTest.java +++ b/modules/core/src/test/java/com/illposed/osc/transport/OSCPortTest.java @@ -326,6 +326,44 @@ public void testSocketAutoClose() throws Exception { .build(); } + @Test + public void testUseSameTransportForOutAndIn() throws Exception { + + if (sender != null) { + sender.close(); + } + + sender = new OSCPortOutBuilder() + .setRemoteSocketAddress(new InetSocketAddress(4711)) + .setLocalSocketAddress(new InetSocketAddress( 4711)) + .setNetworkProtocol(NetworkProtocol.UDP) + .build(); + + // create new receiver based on sender's transport implementation + receiver = new OSCPortInBuilder() + .setTransport(sender.getTransport()) + .build(); + + Assert.assertEquals("expected same transport for both sender and receiver", + sender.getTransport(), receiver.getTransport()); + + // exchange simple message + OSCMessage message = new OSCMessage("/message/receiving"); + SimpleOSCMessageListener listener = new SimpleOSCMessageListener(); + receiver.getDispatcher().addListener(new OSCPatternAddressMessageSelector("/message/receiving"), + listener); + + receiver.startListening(); + sender.send(message); + + // as the socket for sending is the same as for receiving, we will just produce an echo here + assertMessageReceived(listener, WAIT_FOR_RECEIVE_MS); + + // manually close here before tearDown() + receiver.close(); + sender.close(); + } + private void assertMessageReceived( SimpleOSCMessageListener listener, int timeout) { assertEventuallyTrue( From 7e17278f957e5e6b0cc72bab3485447f05a292cb Mon Sep 17 00:00:00 2001 From: Bruno MATEU Date: Fri, 18 Apr 2025 00:46:37 +0200 Subject: [PATCH 2/4] Add OSCPortIn constructor using existing transport and default listeners --- .../src/main/java/com/illposed/osc/transport/OSCPortIn.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortIn.java b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortIn.java index c247f0c6..c0651fa9 100644 --- a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortIn.java +++ b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortIn.java @@ -108,6 +108,12 @@ public OSCPortIn( this.packetListeners = packetListeners; } + public OSCPortIn( + final Transport transport) + { + this(transport, defaultPacketListeners()); + } + /** * Create an OSC-Port that listens on the given local socket for packets from {@code remote}, * using a parser created with the given factory, From 22cda29ab88593cf9a77d5c277e77adb7ab70a18 Mon Sep 17 00:00:00 2001 From: Bruno MATEU Date: Fri, 18 Apr 2025 01:13:36 +0200 Subject: [PATCH 3/4] Process code review comments --- .../com/illposed/osc/transport/OSCPort.java | 2 +- .../osc/transport/OSCPortInBuilder.java | 20 +++++++++---------- .../osc/transport/OSCPortOutBuilder.java | 20 +++++++++---------- .../parent/src/main/resources/checkstyle.xml | 1 + 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/modules/core/src/main/java/com/illposed/osc/transport/OSCPort.java b/modules/core/src/main/java/com/illposed/osc/transport/OSCPort.java index 0552fa52..b95e2daf 100644 --- a/modules/core/src/main/java/com/illposed/osc/transport/OSCPort.java +++ b/modules/core/src/main/java/com/illposed/osc/transport/OSCPort.java @@ -74,7 +74,7 @@ protected OSCPort( final Transport transport) { if (transport == null) { - throw new IllegalStateException( + throw new NullPointerException( "Can not use NULL as transport" ); } diff --git a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortInBuilder.java b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortInBuilder.java index 94b27150..ff86208d 100644 --- a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortInBuilder.java +++ b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortInBuilder.java @@ -85,8 +85,8 @@ public OSCPortIn build() throws IOException { public OSCPortInBuilder setPort(final int port) { final SocketAddress address = new InetSocketAddress(port); - local = address; - remote = address; + this.local = address; + this.remote = address; return this; } @@ -101,18 +101,18 @@ public OSCPortInBuilder setRemotePort(final int port) { } public OSCPortInBuilder setSocketAddress(final SocketAddress address) { - local = address; - remote = address; + this.local = address; + this.remote = address; return this; } public OSCPortInBuilder setLocalSocketAddress(final SocketAddress address) { - local = address; + this.local = address; return this; } public OSCPortInBuilder setRemoteSocketAddress(final SocketAddress address) { - remote = address; + this.remote = address; return this; } @@ -121,15 +121,15 @@ public OSCPortInBuilder setNetworkProtocol(final NetworkProtocol protocol) { return this; } - public OSCPortInBuilder setTransport(final Transport networkTransport) { - transport = networkTransport; + public OSCPortInBuilder setTransport(final Transport transport) { + this.transport = transport; return this; } public OSCPortInBuilder setPacketListeners( - final List listeners) + final List packetListeners) { - packetListeners = listeners; + this.packetListeners = packetListeners; return this; } diff --git a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOutBuilder.java b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOutBuilder.java index e90eed8f..86818071 100644 --- a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOutBuilder.java +++ b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOutBuilder.java @@ -63,8 +63,8 @@ public OSCPortOut build() throws IOException { public OSCPortOutBuilder setPort(final int port) { final SocketAddress address = new InetSocketAddress(port); - local = address; - remote = address; + this.local = address; + this.remote = address; return this; } @@ -79,28 +79,28 @@ public OSCPortOutBuilder setLocalPort(final int port) { } public OSCPortOutBuilder setSocketAddress(final SocketAddress address) { - local = address; - remote = address; + this.local = address; + this.remote = address; return this; } public OSCPortOutBuilder setLocalSocketAddress(final SocketAddress address) { - local = address; + this.local = address; return this; } public OSCPortOutBuilder setRemoteSocketAddress(final SocketAddress address) { - remote = address; + this.remote = remote; return this; } - public OSCPortOutBuilder setNetworkProtocol(final NetworkProtocol protocol) { - networkProtocol = protocol; + public OSCPortOutBuilder setNetworkProtocol(final NetworkProtocol networkProtocol) { + this.networkProtocol = networkProtocol; return this; } - public OSCPortOutBuilder setTransport(final Transport networkTransport) { - transport = networkTransport; + public OSCPortOutBuilder setTransport(final Transport transport) { + this.transport = transport; return this; } } diff --git a/modules/parent/src/main/resources/checkstyle.xml b/modules/parent/src/main/resources/checkstyle.xml index 1d3585fc..19417f4e 100644 --- a/modules/parent/src/main/resources/checkstyle.xml +++ b/modules/parent/src/main/resources/checkstyle.xml @@ -189,6 +189,7 @@ SPDX-License-Identifier: CC0-1.0 + From 758f85fbecd4bc60fcbdea9e1d30ef862e9e45fc Mon Sep 17 00:00:00 2001 From: Bruno MATEU Date: Fri, 18 Apr 2025 01:19:25 +0200 Subject: [PATCH 4/4] Fix some Port In/Out builders setters naming --- .../osc/transport/OSCPortInBuilder.java | 38 +++++++++---------- .../osc/transport/OSCPortOutBuilder.java | 38 +++++++++---------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortInBuilder.java b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortInBuilder.java index ff86208d..fab88bb3 100644 --- a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortInBuilder.java +++ b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortInBuilder.java @@ -21,8 +21,8 @@ public class OSCPortInBuilder { private OSCSerializerAndParserBuilder parserBuilder; private List packetListeners; - private SocketAddress local; - private SocketAddress remote; + private SocketAddress localSocketAddress; + private SocketAddress remoteSocketAddress; private NetworkProtocol networkProtocol = NetworkProtocol.UDP; private Transport transport; @@ -45,12 +45,12 @@ public OSCPortIn build() throws IOException { // If transport is set, other settings cannot be used if (transport != null) { - if (remote != null) { + if (remoteSocketAddress != null) { throw new IllegalArgumentException( "Cannot use remote socket address / port in conjunction with transport object."); } - if (local != null) { + if (localSocketAddress != null) { throw new IllegalArgumentException( "Cannot use local socket address / port in conjunction with transport object."); } @@ -65,13 +65,13 @@ public OSCPortIn build() throws IOException { ); } - if (local == null) { + if (localSocketAddress == null) { throw new IllegalArgumentException( "Missing local socket address / port."); } - if (remote == null) { - remote = new InetSocketAddress(OSCPort.generateWildcard(local), 0); + if (remoteSocketAddress == null) { + remoteSocketAddress = new InetSocketAddress(OSCPort.generateWildcard(localSocketAddress), 0); } if (parserBuilder == null) { @@ -79,40 +79,40 @@ public OSCPortIn build() throws IOException { } return new OSCPortIn( - parserBuilder, packetListeners, local, remote, networkProtocol + parserBuilder, packetListeners, localSocketAddress, remoteSocketAddress, networkProtocol ); } public OSCPortInBuilder setPort(final int port) { final SocketAddress address = new InetSocketAddress(port); - this.local = address; - this.remote = address; + this.localSocketAddress = address; + this.remoteSocketAddress = address; return this; } public OSCPortInBuilder setLocalPort(final int port) { - local = new InetSocketAddress(port); + localSocketAddress = new InetSocketAddress(port); return this; } public OSCPortInBuilder setRemotePort(final int port) { - remote = new InetSocketAddress(port); + remoteSocketAddress = new InetSocketAddress(port); return this; } - public OSCPortInBuilder setSocketAddress(final SocketAddress address) { - this.local = address; - this.remote = address; + public OSCPortInBuilder setSocketAddress(final SocketAddress socketAddress) { + this.localSocketAddress = socketAddress; + this.remoteSocketAddress = socketAddress; return this; } - public OSCPortInBuilder setLocalSocketAddress(final SocketAddress address) { - this.local = address; + public OSCPortInBuilder setLocalSocketAddress(final SocketAddress localSocketAddress) { + this.localSocketAddress = localSocketAddress; return this; } - public OSCPortInBuilder setRemoteSocketAddress(final SocketAddress address) { - this.remote = address; + public OSCPortInBuilder setRemoteSocketAddress(final SocketAddress remoteSocketAddress) { + this.remoteSocketAddress = remoteSocketAddress; return this; } diff --git a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOutBuilder.java b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOutBuilder.java index 86818071..03ada849 100644 --- a/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOutBuilder.java +++ b/modules/core/src/main/java/com/illposed/osc/transport/OSCPortOutBuilder.java @@ -14,8 +14,8 @@ public class OSCPortOutBuilder { private OSCSerializerAndParserBuilder serializerBuilder; - private SocketAddress remote; - private SocketAddress local; + private SocketAddress remoteSocketAddress; + private SocketAddress localSocketAddress; private NetworkProtocol networkProtocol = NetworkProtocol.UDP; private Transport transport; @@ -23,12 +23,12 @@ public OSCPortOut build() throws IOException { // If transport is set, other settings cannot be used if (transport != null) { - if (remote != null) { + if (remoteSocketAddress != null) { throw new IllegalArgumentException( "Cannot use remote socket address / port in conjunction with transport."); } - if (local != null) { + if (localSocketAddress != null) { throw new IllegalArgumentException( "Cannot use local socket address / port in conjunction with transport."); } @@ -43,13 +43,13 @@ public OSCPortOut build() throws IOException { ); } - if (remote == null) { + if (remoteSocketAddress == null) { throw new IllegalArgumentException( "Missing remote socket address / port."); } - if (local == null) { - local = new InetSocketAddress(OSCPort.generateWildcard(remote), 0); + if (localSocketAddress == null) { + localSocketAddress = new InetSocketAddress(OSCPort.generateWildcard(remoteSocketAddress), 0); } if (serializerBuilder == null) { @@ -57,40 +57,40 @@ public OSCPortOut build() throws IOException { } return new OSCPortOut( - serializerBuilder, remote, local, networkProtocol + serializerBuilder, remoteSocketAddress, localSocketAddress, networkProtocol ); } public OSCPortOutBuilder setPort(final int port) { final SocketAddress address = new InetSocketAddress(port); - this.local = address; - this.remote = address; + this.localSocketAddress = address; + this.remoteSocketAddress = address; return this; } public OSCPortOutBuilder setRemotePort(final int port) { - remote = new InetSocketAddress(port); + remoteSocketAddress = new InetSocketAddress(port); return this; } public OSCPortOutBuilder setLocalPort(final int port) { - local = new InetSocketAddress(port); + localSocketAddress = new InetSocketAddress(port); return this; } - public OSCPortOutBuilder setSocketAddress(final SocketAddress address) { - this.local = address; - this.remote = address; + public OSCPortOutBuilder setSocketAddress(final SocketAddress socketAddress) { + this.localSocketAddress = socketAddress; + this.remoteSocketAddress = socketAddress; return this; } - public OSCPortOutBuilder setLocalSocketAddress(final SocketAddress address) { - this.local = address; + public OSCPortOutBuilder setLocalSocketAddress(final SocketAddress localSocketAddress) { + this.localSocketAddress = localSocketAddress; return this; } - public OSCPortOutBuilder setRemoteSocketAddress(final SocketAddress address) { - this.remote = remote; + public OSCPortOutBuilder setRemoteSocketAddress(final SocketAddress remoteSocketAddress) { + this.remoteSocketAddress = remoteSocketAddress; return this; }