Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions examples/receiver_tcp_slip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
extern crate rosc;

use rosc::decoder::decode_tcp_slip;
use rosc::OscPacket;
use std::env;
use std::io::Read;
use std::net::{SocketAddrV4, TcpListener, TcpStream};
use std::str::FromStr;

fn main() {
let args: Vec<String> = env::args().collect();
let usage = format!("Usage {} [bind]|[conn] IP:PORT\n Use bind to open a local TCP socket at address, use conn to connect to the given addres", args[0]);
if args.len() < 3 {
println!("{}", usage);
::std::process::exit(1)
}
println!("{:?}", args);
let addr = match SocketAddrV4::from_str(&args[2]) {
Ok(addr) => addr,
Err(_) => panic!("{}", usage),
};

if let Some(mut stream) = if args[1].as_str() == "bind" {
let listener = TcpListener::bind(addr).unwrap();
match listener.accept() {
Ok((stream, addr)) => {
println!("Client Connected to {}", addr);
Some(stream)
}
Err(e) => {
println!("Error accepting TCP: {}", e);
None
}
}
} else if args[1].as_str() == "conn" {
let stream = Some(TcpStream::connect(addr).unwrap());
println!("Connected to {}", addr);
stream
} else {
panic!("{}", usage);
} {
let mut buf = [0u8; rosc::decoder::MTU];

loop {
match stream.read(&mut buf) {
Ok(0) => {
// End-Of-File
}
Ok(size) => {
println!("Received packet with size {} from: {}", size, addr);

let mut slice = &buf[0..size];

while let Some(remainder) = match decode_tcp_slip(slice) {
Ok((_remainder, None)) => {
// Break the loop when we get None - we need more data
None
}
Ok((remainder, Some(packet))) => {
handle_packet(packet);
if remainder.is_empty() {
None
} else {
Some(remainder)
}
}
Err(e) => {
println!("Error parsing OscPacket: {}", e);
None
}
} {
slice = remainder;
}
}
Err(e) => {
match e.kind() {
std::io::ErrorKind::ConnectionReset => println!("Client disconnected"),
_ => println!("Error reading TCP stream: {}", e),
}
break;
}
}
}
}
}

fn handle_packet(packet: OscPacket) {
match packet {
OscPacket::Message(msg) => {
println!("OSC address: {}", msg.addr);
println!("OSC arguments: {:?}", msg.args);
}
OscPacket::Bundle(bundle) => {
println!("OSC Bundle: {:?}", bundle);
}
}
}
2 changes: 1 addition & 1 deletion examples/sender_tcp.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extern crate rosc;

use rosc::encoder::{self, Output};
use rosc::encoder::{self};
use rosc::{OscMessage, OscPacket, OscType};
use std::io::Write;
use std::net::{SocketAddrV4, TcpStream};
Expand Down
54 changes: 54 additions & 0 deletions examples/sender_tcp_slip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
extern crate rosc;

use rosc::encoder::{self};
use rosc::{OscMessage, OscPacket, OscType};
use std::io::Write;
use std::net::{SocketAddrV4, TcpStream};
use std::str::FromStr;
use std::time::Duration;
use std::{env, f32, thread};

fn get_addr_from_arg(arg: &str) -> SocketAddrV4 {
SocketAddrV4::from_str(arg).unwrap()
}

fn main() {
let args: Vec<String> = env::args().collect();
let usage = format!("Usage: {} IP:PORT", &args[0]);
if args.len() < 2 {
panic!("{}", usage);
}
let addr = get_addr_from_arg(&args[1]);
let mut stream = TcpStream::connect(addr).unwrap();

// switch view
let msg_buf = encoder::encode_tcp_slip(&OscPacket::Message(OscMessage {
addr: "/3".to_string(),
args: vec![],
}))
.unwrap();

stream.write_all(&msg_buf).unwrap();

// send random values to xy fields
let steps = 128;
let step_size: f32 = 2.0 * f32::consts::PI / steps as f32;
for i in 0.. {
let x = 0.5 + (step_size * (i % steps) as f32).sin() / 2.0;
let y = 0.5 + (step_size * (i % steps) as f32).cos() / 2.0;
let mut msg_buf = encoder::encode_tcp_slip(&OscPacket::Message(OscMessage {
addr: "/3/xy1".to_string(),
args: vec![OscType::Float(x), OscType::Float(y)],
}))
.unwrap();

stream.write_all(&msg_buf).unwrap();
msg_buf = encoder::encode_tcp_slip(&OscPacket::Message(OscMessage {
addr: "/3/xy2".to_string(),
args: vec![OscType::Float(y), OscType::Float(x)],
}))
.unwrap();
stream.write_all(&msg_buf).unwrap();
thread::sleep(Duration::from_millis(20));
}
}
85 changes: 85 additions & 0 deletions src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ use nom::{combinator::map_res, sequence::tuple, Err, IResult};
/// Common MTU size for ethernet
pub const MTU: usize = 1536;

/// SLIP protocol special characters
pub const SLIP_END: u8 = 0xC0;
pub const SLIP_ESC: u8 = 0xDB;
pub const SLIP_ESC_END: u8 = 0xDC;
pub const SLIP_ESC_ESC: u8 = 0xDD;

/// Takes a bytes slice representing a UDP packet and returns the OSC packet as well as a slice of
/// any bytes remaining after the OSC packet.
pub fn decode_udp(msg: &[u8]) -> Result<(&[u8], OscPacket), OscError> {
Expand Down Expand Up @@ -65,6 +71,85 @@ pub fn decode_tcp(msg: &[u8]) -> Result<(&[u8], Option<OscPacket>), OscError> {

/// Takes a bytes slice from a TCP stream (or any stream-based protocol) and returns a vec of all
/// OSC packets in the slice as well as a slice of the bytes remaining after the last packet.
/// Takes a bytes slice from a TCP stream using OSC 1.1 with SLIP encoding and returns the first OSC
/// packet as well as a slice of the bytes remaining after the packet.
///
/// # OSC 1.1 and SLIP
///
/// OSC 1.1 employs SLIP (RFC1055) encoding with a double END character
/// sequence for packet boundaries. SLIP special characters are:
/// - END (0xC0): Marks packet boundaries
/// - ESC (0xDB): Escape character
/// - ESC_END (0xDC): Escaped END character
/// - ESC_ESC (0xDD): Escaped ESC character
pub fn decode_tcp_slip(msg: &[u8]) -> Result<(&[u8], Option<OscPacket>), OscError> {
// Check for minimum size (END character + message)
if msg.len() < 2 {
return Ok((msg, None));
}

// Find the start of the packet (single END)
let mut start_idx = 0;
while start_idx < msg.len() {
if msg[start_idx] == SLIP_END {
start_idx += 1;
break;
}
start_idx += 1;
}

if start_idx + 8 > msg.len() {
return Ok((msg, None));
}

let input = &msg[start_idx..];

// Un-SLIP the packet data
let mut decoded = Vec::new();
let mut i = 0;
let mut ended = false;
while i < input.len() {
match input[i] {
SLIP_END => {
// Found end of packet
ended = true;
break;
}
SLIP_ESC => {
if i + 1 >= input.len() {
// Escape sequence cut short by the buffer boundary; not
// necessarily invalid, just need more data from the stream.
return Ok((msg, None));
}
match input[i + 1] {
SLIP_ESC_END => decoded.push(SLIP_END),
SLIP_ESC_ESC => decoded.push(SLIP_ESC),
_ => return Err(OscError::BadPacket("Invalid SLIP escape sequence")),
}
i += 2;
}
b => {
decoded.push(b);
i += 1;
}
}
}

if !ended {
// No terminating END in the buffer yet; wait for more data.
return Ok((msg, None));
}

// Decode the OSC packet from the un-SLIP'd data
match decode_packet(&decoded, &decoded) {
Ok((_, osc_packet)) => Ok((&input[i + 1..], Some(osc_packet))),
Err(e) => match e {
Err::Incomplete(_) => Err(OscError::BadPacket("Incomplete data")),
Err::Error(e) | Err::Failure(e) => Err(e),
},
}
}

pub fn decode_tcp_vec(msg: &[u8]) -> Result<(&[u8], Vec<OscPacket>), OscError> {
let mut input = msg;
let mut osc_packets = vec![];
Expand Down
34 changes: 34 additions & 0 deletions src/encoder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::alloc::{string::String, vec::Vec};
use crate::decoder::{SLIP_ESC, SLIP_ESC_END, SLIP_ESC_ESC, SLIP_END};
use crate::types::{OscBundle, OscMessage, OscPacket, OscTime, OscType};

/// Takes a reference to an OSC packet and returns
Expand Down Expand Up @@ -27,6 +28,39 @@ pub fn encode(packet: &OscPacket) -> crate::types::Result<Vec<u8>> {
Ok(bytes)
}

/// Works exactly the same as [encode()]. Except that it uses SLIP encoding (RFC1055) as per the
/// OSC 1.1 specification. The packet is wrapped with END characters and any END or ESC characters
/// within the packet are properly escaped.
pub fn encode_tcp_slip(packet: &OscPacket) -> crate::types::Result<Vec<u8>> {
let mut bytes = Vec::new();

// Start with END character
bytes.push(SLIP_END);

// Encode the packet
let packet_bytes = encode(packet)?;

// SLIP encode the packet bytes
for &b in packet_bytes.iter() {
match b {
SLIP_END => {
bytes.push(SLIP_ESC);
bytes.push(SLIP_ESC_END);
}
SLIP_ESC => {
bytes.push(SLIP_ESC);
bytes.push(SLIP_ESC_ESC);
}
_ => bytes.push(b),
}
}

// End with END character
bytes.push(SLIP_END);

Ok(bytes)
}

/// Works exactly the same as [encode()]. Except that it prepends the length of the message into
/// the first 4 bytes of the returned Vec, as per the OSC 1.0 specification.
pub fn encode_tcp(packet: &OscPacket) -> crate::types::Result<Vec<u8>> {
Expand Down
Loading