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
6 changes: 3 additions & 3 deletions crates/buttplug_core/src/connector/transport/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::connector::{
use displaydoc::Display;
use futures::future::BoxFuture;
use thiserror::Error;
use std::net::SocketAddr;
use tokio::sync::mpsc::{Receiver, Sender};

/// Messages we can receive from a connector.
Expand Down Expand Up @@ -44,10 +45,9 @@ pub trait ButtplugConnectorTransport: Send + Sync {
pub enum ButtplugConnectorTransportSpecificError {
#[error("Network error: {0}")]
GenericNetworkError(String),
#[error("Socket bind error on {address}:{port}: {kind:?}: {message}")]
#[error("Socket bind error on {address}: {kind:?}: {message}")]
SocketBindError {
address: String,
port: u16,
address: SocketAddr,
kind: std::io::ErrorKind,
message: String,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use buttplug_core::{
message::serializer::ButtplugSerializedMessage,
};
use futures::{FutureExt, SinkExt, StreamExt, future::BoxFuture};
use std::{fmt, sync::Arc, time::Duration};
use std::{fmt, net::SocketAddr, sync::Arc, time::Duration};
use tokio::{
net::{TcpListener, TcpStream},
select,
Expand Down Expand Up @@ -51,32 +51,27 @@ impl fmt::Debug for ListenerBoundCallback {

#[derive(Clone, Debug)]
pub struct ButtplugWebsocketServerTransportBuilder {
/// If true, listens all on available interfaces. Otherwise, only listens on 127.0.0.1.
listen_on_all_interfaces: bool,
/// Insecure port for listening for websocket connections.
port: u16,
/// TCP/IP address for listening for insecure websocket connections; defaults to localhost:12345
listen_address: SocketAddr,
/// Optional callback fired after the listener is bound and the actual local port is known.
listener_bound_callback: Option<ListenerBoundCallback>,
}

impl Default for ButtplugWebsocketServerTransportBuilder {
fn default() -> Self {
Self {
listen_on_all_interfaces: false,
port: 12345,
listen_address: SocketAddr::new(
std::net::IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1)),
12345,
),
listener_bound_callback: None,
}
}
}

impl ButtplugWebsocketServerTransportBuilder {
pub fn listen_on_all_interfaces(&mut self, listen_on_all_interfaces: bool) -> &mut Self {
self.listen_on_all_interfaces = listen_on_all_interfaces;
self
}

pub fn port(&mut self, port: u16) -> &mut Self {
self.port = port;
pub fn listen_address(&mut self, listen_address: SocketAddr) -> &mut Self {
self.listen_address = listen_address;
self
}

Expand All @@ -87,8 +82,7 @@ impl ButtplugWebsocketServerTransportBuilder {

pub fn finish(&self) -> ButtplugWebsocketServerTransport {
ButtplugWebsocketServerTransport {
port: self.port,
listen_on_all_interfaces: self.listen_on_all_interfaces,
listen_address: self.listen_address.clone(),
listener_bound_callback: self.listener_bound_callback.clone(),
disconnect_notifier: Arc::new(Notify::new()),
}
Expand Down Expand Up @@ -222,8 +216,7 @@ async fn run_connection_loop(

/// Websocket connector for ButtplugClients, using [tokio_tungstenite]
pub struct ButtplugWebsocketServerTransport {
port: u16,
listen_on_all_interfaces: bool,
listen_address: SocketAddr,
listener_bound_callback: Option<ListenerBoundCallback>,
disconnect_notifier: Arc<Notify>,
}
Expand All @@ -237,15 +230,7 @@ impl ButtplugConnectorTransport for ButtplugWebsocketServerTransport {
let disconnect_notifier = self.disconnect_notifier.clone();
let listener_bound_callback = self.listener_bound_callback.clone();

let base_addr = if self.listen_on_all_interfaces {
"0.0.0.0"
} else {
"127.0.0.1"
};

let address = base_addr.to_owned();
let port = self.port;
let addr = format!("{}:{}", address, port);
let addr = self.listen_address.clone();
debug!("Websocket: Trying to listen on {}", addr);
let response_sender_clone = incoming_sender;
let disconnect_notifier_clone = disconnect_notifier;
Expand All @@ -256,8 +241,7 @@ impl ButtplugConnectorTransport for ButtplugWebsocketServerTransport {
let listener = try_socket.map_err(|e| {
ButtplugConnectorError::TransportSpecificError(
ButtplugConnectorTransportSpecificError::SocketBindError {
address,
port,
address: addr,
kind: e.kind(),
message: e.to_string(),
},
Expand Down
47 changes: 43 additions & 4 deletions crates/intiface_engine/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,18 @@ pub struct IntifaceCLIArguments {
/// listen on 127.0.0.1.
#[argh(switch)]
#[getset(get_copy = "pub")]
websocket_use_all_interfaces: bool,
websocket_use_all_interfaces: Option<bool>,

/// insecure port for websocket servers.
#[argh(option)]
#[getset(get_copy = "pub")]
websocket_port: Option<u16>,

/// address on which the websocket server listens for insecure connections
#[argh(option)]
#[getset(get = "pub")]
websocket_listen_address: Option<String>,

/// insecure address for connecting to websocket servers.
#[argh(option)]
#[getset(get = "pub")]
Expand Down Expand Up @@ -239,7 +244,6 @@ impl TryFrom<IntifaceCLIArguments> for EngineOptions {
}

builder
.websocket_use_all_interfaces(args.websocket_use_all_interfaces())
.use_bluetooth_le(args.use_bluetooth_le())
.use_serial_port(args.use_serial())
.use_hid(args.use_hid())
Expand All @@ -259,9 +263,44 @@ impl TryFrom<IntifaceCLIArguments> for EngineOptions {
.crash_task_thread(args.crash_task_thread());
}

if let Some(value) = args.websocket_port() {
builder.websocket_port(value);
/*
* websocket_listen_address supplants websocket_use_all_interfaces and
* websocket_port, but we want to keep the latter two for backwards
* compatibility. Ensure that, if the former is given, neither of the
* latter two have been.
*/
let maybe_listen_address = match args.websocket_listen_address() {
None => {
match args.websocket_port() {
None => Ok(None), // no listen address & no port: don't listen
Some(port) => {
let base_addr =
if args.websocket_use_all_interfaces().unwrap_or(false) {
"0.0.0.0"
} else {
"127.0.0.1"
};
Ok(Some(format!("{base_addr}:{port}")))
}
}
}
Some(address) => match (args.websocket_use_all_interfaces(), args.websocket_port()) {
(None, None) => Ok(Some(address.to_owned())),
(Some(_), None) => Err(IntifaceError::new(
"websocket-use-all-interfaces conflicts with websocket-listen-address",
)),
(None, Some(_)) => Err(IntifaceError::new(
"websocket-use-all-interfaces conflicts with websocket-port",
)),
(Some(_), Some(_)) => Err(IntifaceError::new(
"websocket-use-all-interfaces conflicts with both websocket-port and websocket-use-all-interfaces",
)),
},
};
if let Some(listen_address) = maybe_listen_address? {
builder.websocket_listen_address(&listen_address);
}

if let Some(value) = args.websocket_client_address() {
builder.websocket_client_address(value);
}
Expand Down
13 changes: 9 additions & 4 deletions crates/intiface_engine/src/buttplug_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,16 @@ pub async fn run_server(
options: &EngineOptions,
on_listener_bound: Option<Arc<dyn Fn(u16) + Send + Sync>>,
) -> Result<(), ButtplugServerConnectorError> {
if let Some(port) = options.websocket_port() {
if let Some(listen_address) = options.websocket_listen_address() {
let mut transport_builder = ButtplugWebsocketServerTransportBuilder::default();
transport_builder
.port(port)
.listen_on_all_interfaces(options.websocket_use_all_interfaces());

let parsed_listen_address = listen_address.parse().map_err(|pe| {
ButtplugServerConnectorError::ConnectorError(
buttplug_core::connector::ButtplugConnectorError::ConnectorGenericError(
format!("Could not parse provided websocket-listen-address: {pe}")
))})?;

transport_builder.listen_address(parsed_listen_address);
if let Some(on_listener_bound) = on_listener_bound {
transport_builder.on_listener_bound(move |bound_port| {
on_listener_bound(bound_port);
Expand Down
5 changes: 2 additions & 3 deletions crates/intiface_engine/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,11 @@ fn websocket_port_in_use_error(err: &ButtplugServerConnectorError) -> Option<(St
ButtplugConnectorError::TransportSpecificError(
ButtplugConnectorTransportSpecificError::SocketBindError {
address,
port,
kind,
message: _,
},
),
) if *kind == ErrorKind::AddrInUse => Some((address.clone(), *port)),
) if *kind == ErrorKind::AddrInUse => Some((address.ip().to_string(), address.port())),
_ => None,
}
}
Expand Down Expand Up @@ -154,7 +153,7 @@ impl IntifaceEngine {
}

let mdns_service_metadata =
if options.broadcast_server_mdns() && options.websocket_port().is_some() {
if options.broadcast_server_mdns() && options.websocket_listen_address().is_some() {
Some(Arc::new(IntifaceMdnsServiceMetadata::new(
options.mdns_suffix().as_deref(),
)))
Expand Down
21 changes: 6 additions & 15 deletions crates/intiface_engine/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ pub struct EngineOptions {
user_device_config_path: Option<String>,
#[getset(get = "pub")]
server_name: String,
#[getset(get_copy = "pub")]
websocket_use_all_interfaces: bool,
#[getset(get_copy = "pub")]
websocket_port: Option<u16>,
#[getset(get = "pub")]
websocket_listen_address: Option<String>,
#[getset(get = "pub")]
websocket_client_address: Option<String>,
#[getset(get_copy = "pub")]
Expand Down Expand Up @@ -75,8 +73,7 @@ pub struct EngineOptionsExternal {
pub user_device_config_json: Option<String>,
pub user_device_config_path: Option<String>,
pub server_name: String,
pub websocket_use_all_interfaces: bool,
pub websocket_port: Option<u16>,
pub websocket_listen_address: Option<String>,
pub websocket_client_address: Option<String>,
pub frontend_websocket_port: Option<u16>,
pub frontend_in_process_channel: bool,
Expand Down Expand Up @@ -109,8 +106,7 @@ impl From<EngineOptionsExternal> for EngineOptions {
user_device_config_json: other.user_device_config_json,
user_device_config_path: other.user_device_config_path,
server_name: other.server_name,
websocket_use_all_interfaces: other.websocket_use_all_interfaces,
websocket_port: other.websocket_port,
websocket_listen_address: other.websocket_listen_address,
websocket_client_address: other.websocket_client_address,
frontend_websocket_port: other.frontend_websocket_port,
frontend_in_process_channel: other.frontend_in_process_channel,
Expand Down Expand Up @@ -182,8 +178,8 @@ impl EngineOptionsBuilder {
self
}

pub fn websocket_use_all_interfaces(&mut self, value: bool) -> &mut Self {
self.options.websocket_use_all_interfaces = value;
pub fn websocket_listen_address(&mut self, address: &str) -> &mut Self {
self.options.websocket_listen_address = Some(address.to_owned());
self
}

Expand Down Expand Up @@ -232,11 +228,6 @@ impl EngineOptionsBuilder {
self
}

pub fn websocket_port(&mut self, port: u16) -> &mut Self {
self.options.websocket_port = Some(port);
self
}

pub fn websocket_client_address(&mut self, address: &str) -> &mut Self {
self.options.websocket_client_address = Some(address.to_owned());
self
Expand Down