Compare commits
No commits in common. "7aec740306dce26ab7ce4f0060c176920f88d8a4" and "0d499e4fb01084cd7f90eb58a0456f7dd727542d" have entirely different histories.
7aec740306
...
0d499e4fb0
File diff suppressed because it is too large
Load Diff
27
Cargo.toml
27
Cargo.toml
|
@ -1,25 +1,28 @@
|
||||||
[package]
|
[package]
|
||||||
name = "mumble-web-proxy"
|
name = "mumble-web-proxy"
|
||||||
version = "0.1.1"
|
version = "0.1.0"
|
||||||
authors = ["Jonas Herzig <me@johni0702.de>"]
|
authors = ["Jonas Herzig <me@johni0702.de>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
argparse = "0.2.2"
|
argparse = "0.2.2"
|
||||||
bytes = "1"
|
bytes = "0.5"
|
||||||
byteorder = "1.5"
|
byteorder = "1.2"
|
||||||
futures = { version = "0.3", features = ["compat", "io-compat"] }
|
futures = { version = "0.3", features = ["compat", "io-compat"] }
|
||||||
toml = "0.8"
|
toml = "0.5"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "0.2", features = ["full"] }
|
||||||
tokio-util = { version = "0.6.10", features = ["codec"] }
|
tokio-util = { version = "0.3", features = ["codec"] }
|
||||||
tokio-native-tls = "0.3"
|
tokio-tls = "0.3"
|
||||||
native-tls = "0.2"
|
native-tls = "0.2"
|
||||||
mumble-protocol = { version = "0.4", features = ["webrtc-extensions"] }
|
mumble-protocol = { version = "0.3", features = ["webrtc-extensions"] }
|
||||||
tokio-tungstenite = "0.13"
|
tokio-tungstenite = "0.10"
|
||||||
http = "0.2"
|
http = "0.2"
|
||||||
tungstenite = "0.12"
|
tungstenite = "0.10"
|
||||||
rtp = { git = "https://git.danksquad.org/anon/rtp", branch = "dtls-srtp", features = ["rfc5764-openssl"] }
|
rtp = { git = "https://github.com/johni0702/rtp", rev = "1444b3c", features = ["rfc5764-openssl"] }
|
||||||
libnice = "0.3"
|
libnice = "0.2"
|
||||||
webrtc-sdp = "0.3"
|
webrtc-sdp = "0.3"
|
||||||
openssl = "0.10"
|
openssl = "0.10"
|
||||||
|
|
||||||
|
[replace]
|
||||||
|
"rust-crypto:0.2.36" = { git = "https://github.com/awmath/rust-crypto.git", branch = "avx2" }
|
||||||
|
|
|
@ -13,7 +13,7 @@ Note that it requires an extension to the Mumble protocol which has not yet been
|
||||||
|
|
||||||
#### Prerequisites
|
#### Prerequisites
|
||||||
|
|
||||||
- Rust 1.45+ (e.g. via [rustup](https://rustup.rs/))
|
- Rust 1.39+ (e.g. via [rustup](https://rustup.rs/))
|
||||||
- libnice development headers (`libnice-devel` on Fedora, `libnice-dev` on Debian)
|
- libnice development headers (`libnice-devel` on Fedora, `libnice-dev` on Debian)
|
||||||
- OpenSSL development headers (`openssl-devel` on Fedora, `libssl-dev` on Debian)
|
- OpenSSL development headers (`openssl-devel` on Fedora, `libssl-dev` on Debian)
|
||||||
- clang (`clang` on Fedora and Debian)
|
- clang (`clang` on Fedora and Debian)
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
FROM rust:1.48-alpine AS build
|
|
||||||
|
|
||||||
ARG REV=master
|
|
||||||
|
|
||||||
RUN apk add --no-cache \
|
|
||||||
clang-libs \
|
|
||||||
curl \
|
|
||||||
libc-dev \
|
|
||||||
libnice-dev \
|
|
||||||
openssl-dev \
|
|
||||||
;
|
|
||||||
WORKDIR /src
|
|
||||||
RUN curl https://codeload.github.com/Johni0702/mumble-web-proxy/tar.gz/$REV \
|
|
||||||
| tar -xzf - --strip-components 1
|
|
||||||
RUN echo -e '\n[dependencies."async-trait"]\ndefault-features = false' >> Cargo.toml
|
|
||||||
RUN RUSTFLAGS="-C target-feature=-crt-static" cargo install --path .
|
|
||||||
|
|
||||||
FROM alpine
|
|
||||||
|
|
||||||
RUN apk add --no-cache \
|
|
||||||
bash \
|
|
||||||
libgcc \
|
|
||||||
libnice \
|
|
||||||
;
|
|
||||||
COPY --from=build /usr/local/cargo/bin/mumble-web-proxy /mumble-web-proxy
|
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
|
||||||
|
|
||||||
ENV MWP_LISTEN_WS=64737
|
|
||||||
ENV MWP_SERVER=mumble-server:64738
|
|
||||||
ENV MWP_ACCEPT_INVALID_CERTIFICATE=
|
|
||||||
ENV MWP_ICE_PORT_MIN=
|
|
||||||
ENV MWP_ICE_PORT_MAX=
|
|
||||||
ENV MWP_ICE_IPV4=
|
|
||||||
ENV MWP_ICE_IPV6=
|
|
||||||
|
|
||||||
CMD ["/entrypoint.sh"]
|
|
||||||
USER 1000
|
|
||||||
EXPOSE 64737
|
|
|
@ -1,13 +0,0 @@
|
||||||
# mumble-web-proxy OCI image
|
|
||||||
|
|
||||||
This directory provides files to build a mumble-web-proxy OCI image.
|
|
||||||
The image is based on Alpine Linux and is less than 30 MiB in size.
|
|
||||||
One can use [Docker](https://www.docker.com/) in order to build the image,
|
|
||||||
as follows.
|
|
||||||
|
|
||||||
```
|
|
||||||
docker build --build-arg REV=master -t mumble-web-proxy .
|
|
||||||
```
|
|
||||||
|
|
||||||
`master` can be replaced by any revision (i.e. branch, tag or commit hash) of
|
|
||||||
this repository.
|
|
|
@ -1,25 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
cmd=("/mumble-web-proxy" "--listen-ws=$MWP_LISTEN_WS" "--server=$MWP_SERVER")
|
|
||||||
|
|
||||||
if [ "$MWP_ACCEPT_INVALID_CERTIFICATE" = true ]; then
|
|
||||||
cmd+=("--accept-invalid-certificate")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$MWP_ICE_PORT_MIN" ]; then
|
|
||||||
cmd+=("--ice-port-min=$MWP_ICE_PORT_MIN")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$MWP_ICE_PORT_MAX" ]; then
|
|
||||||
cmd+=("--ice-port-max=$MWP_ICE_PORT_MAX")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$MWP_ICE_IPV4" ]; then
|
|
||||||
cmd+=("--ice-ipv4=$MWP_ICE_IPV4")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$MWP_ICE_IPV6" ]; then
|
|
||||||
cmd+=("--ice-ipv6=$MWP_ICE_IPV6")
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec "${cmd[@]}"
|
|
|
@ -30,7 +30,7 @@ use std::task::Context;
|
||||||
use std::task::Poll;
|
use std::task::Poll;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::io;
|
use tokio::io;
|
||||||
use tokio::time::Sleep;
|
use tokio::time::Delay;
|
||||||
use webrtc_sdp::attribute_type::SdpAttribute;
|
use webrtc_sdp::attribute_type::SdpAttribute;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
@ -42,7 +42,7 @@ struct User {
|
||||||
session: u32, // mumble session id
|
session: u32, // mumble session id
|
||||||
ssrc: u32, // ssrc id
|
ssrc: u32, // ssrc id
|
||||||
active: bool, // whether the user is currently transmitting audio
|
active: bool, // whether the user is currently transmitting audio
|
||||||
timeout: Option<Pin<Box<Sleep>>>, // assume end of transmission if silent until then
|
timeout: Option<Delay>, // assume end of transmission if silent until then
|
||||||
start_voice_seq_num: u64,
|
start_voice_seq_num: u64,
|
||||||
highest_voice_seq_num: u64,
|
highest_voice_seq_num: u64,
|
||||||
rtp_seq_num_offset: u32, // u32 because we also derive the timestamp from it
|
rtp_seq_num_offset: u32, // u32 because we also derive the timestamp from it
|
||||||
|
@ -70,7 +70,7 @@ impl User {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_active(&mut self, target: u8) -> Option<Frame> {
|
fn set_active(&mut self, target: u8) -> Option<Frame> {
|
||||||
self.timeout = Some(Box::pin(tokio::time::sleep(Duration::from_millis(400))));
|
self.timeout = Some(tokio::time::delay_for(Duration::from_millis(400)));
|
||||||
|
|
||||||
if self.active {
|
if self.active {
|
||||||
None
|
None
|
||||||
|
@ -471,13 +471,7 @@ impl Connection {
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
match packet {
|
match packet {
|
||||||
ControlPacket::Authenticate(mut message) => {
|
ControlPacket::Authenticate(mut message) => {
|
||||||
println!("MSG Authenticate: {:?}", {
|
println!("MSG Authenticate: {:?}", message);
|
||||||
let mut message = message.clone();
|
|
||||||
if message.get_password() != "" {
|
|
||||||
message.set_password("{{snip}}".to_string());
|
|
||||||
}
|
|
||||||
message
|
|
||||||
});
|
|
||||||
if message.get_webrtc() {
|
if message.get_webrtc() {
|
||||||
// strip webrtc support from the connection (we will be providing it)
|
// strip webrtc support from the connection (we will be providing it)
|
||||||
message.clear_webrtc();
|
message.clear_webrtc();
|
||||||
|
@ -587,7 +581,8 @@ impl Future for Connection {
|
||||||
// (same applies to the other futures directly below it)
|
// (same applies to the other futures directly below it)
|
||||||
for session in self.sessions.values_mut() {
|
for session in self.sessions.values_mut() {
|
||||||
if let Some(timeout) = &mut session.timeout {
|
if let Some(timeout) = &mut session.timeout {
|
||||||
if let Poll::Ready(()) = timeout.poll_unpin(cx) {
|
pin_mut!(timeout);
|
||||||
|
if let Poll::Ready(()) = timeout.poll(cx) {
|
||||||
if let Some(frame) = session.set_inactive() {
|
if let Some(frame) = session.set_inactive() {
|
||||||
self.outbound_buf.push_back(frame);
|
self.outbound_buf.push_back(frame);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,12 @@ impl From<native_tls::Error> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<tokio::time::Error> for Error {
|
||||||
|
fn from(e: tokio::time::Error) -> Self {
|
||||||
|
Error::Misc(Box::new(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<rtp::Error> for Error {
|
impl From<rtp::Error> for Error {
|
||||||
fn from(e: rtp::Error) -> Self {
|
fn from(e: rtp::Error) -> Self {
|
||||||
Error::Misc(Box::new(e))
|
Error::Misc(Box::new(e))
|
||||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -16,10 +16,12 @@ use serde::Deserialize;
|
||||||
use std::convert::Into;
|
use std::convert::Into;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
|
use std::net::Ipv4Addr;
|
||||||
|
use std::net::Ipv6Addr;
|
||||||
|
use std::net::ToSocketAddrs;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio_native_tls::TlsConnector;
|
use tokio_tls::TlsConnector;
|
||||||
use tokio_tungstenite::accept_hdr_async_with_config;
|
use tokio_tungstenite::accept_hdr_async_with_config;
|
||||||
use tokio_util::codec::Decoder;
|
use tokio_util::codec::Decoder;
|
||||||
use tungstenite::handshake::server::{ErrorResponse, Request, Response};
|
use tungstenite::handshake::server::{ErrorResponse, Request, Response};
|
||||||
|
@ -176,11 +178,8 @@ async fn main() -> Result<(), Error> {
|
||||||
println!("Resolved upstream address: {}", upstream_addr);
|
println!("Resolved upstream address: {}", upstream_addr);
|
||||||
|
|
||||||
println!("Binding to port {}", ws_port);
|
println!("Binding to port {}", ws_port);
|
||||||
let ipv6_socket_addr = (Ipv6Addr::UNSPECIFIED, ws_port);
|
let socket_addr = (Ipv6Addr::from(0), ws_port);
|
||||||
let ipv4_socket_addr = (Ipv4Addr::UNSPECIFIED, ws_port);
|
let mut server = TcpListener::bind(&socket_addr).await?;
|
||||||
let socket_addrs = [SocketAddr::from(ipv6_socket_addr), SocketAddr::from(ipv4_socket_addr)];
|
|
||||||
|
|
||||||
let server = TcpListener::bind(&socket_addrs[..]).await?;
|
|
||||||
|
|
||||||
println!("Waiting for client connections..");
|
println!("Waiting for client connections..");
|
||||||
loop {
|
loop {
|
||||||
|
@ -213,7 +212,6 @@ async fn main() -> Result<(), Error> {
|
||||||
max_send_queue: Some(10), // can be fairly small as voice is using WebRTC instead
|
max_send_queue: Some(10), // can be fairly small as voice is using WebRTC instead
|
||||||
max_message_size: Some(0x7f_ffff), // maximum size accepted by Murmur
|
max_message_size: Some(0x7f_ffff), // maximum size accepted by Murmur
|
||||||
max_frame_size: Some(0x7f_ffff), // maximum size accepted by Murmur
|
max_frame_size: Some(0x7f_ffff), // maximum size accepted by Murmur
|
||||||
accept_unmasked_frames: false, // browsers should comply with RFC 6455
|
|
||||||
};
|
};
|
||||||
fn header_callback(
|
fn header_callback(
|
||||||
_req: &Request,
|
_req: &Request,
|
||||||
|
|
Loading…
Reference in New Issue