diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | config.mk | 1 | ||||
-rw-r--r-- | include/umumble/constants.h | 78 | ||||
-rw-r--r-- | include/umumble/umumble.h (renamed from include/libumumble.h) | 20 | ||||
-rw-r--r-- | src/connection.c | 14 | ||||
-rw-r--r-- | src/ctx.c | 4 | ||||
-rw-r--r-- | src/message.c | 15 | ||||
-rw-r--r-- | src/proto/MumbleTCP.proto (renamed from src/Mumble.proto) | 2 | ||||
-rw-r--r-- | src/proto/MumbleUDP.proto | 85 | ||||
-rw-r--r-- | tests/Makefile | 3 | ||||
-rw-r--r-- | tests/test.c | 2 |
13 files changed, 206 insertions, 30 deletions
diff --git a/.gitignore b/.gitignore index 76adb92..a6fe2e2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ build/ -tests/build/ *.a *.so *.pb.c diff --git a/Makefile b/Makefile index 0e60318..fc0e340 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ SRC += $(NANOPB_DIR)/pb_common.c PROTO = $(shell find src/ -type f -name '*.proto') OBJ = $(PROTO:%.proto=$(BUILD_DIR)/%.pb.c.o) OBJ += $(SRC:%=$(BUILD_DIR)/%.o) -H = include/libumumble.h +INCLUDE = $(shell find include/) .PHONY: all static shared tests clean install-static install-shared install @@ -31,16 +31,16 @@ $(BUILD_DIR)/%.c.o: %.c mkdir -p '$(@D)' $(CC) -c -o $@ $(INCLUDES) $(CFLAGS) $< -tests: +tests: $(SNAME) $(MAKE) -C tests clean: rm -rf $(SNAME) $(DNAME) $(BUILD_DIR) src/*.pb.h src/*.pb.c $(MAKE) -C tests clean -install-header: $(H) +install-header: $(INCLUDE) install -d $(DESTDIR)$(INCLUDEDIR) - install -m 644 $^ $(DESTDIR)$(INCLUDEDIR) + cp -Rv include/. $(DESTDIR)$(INCLUDEDIR) install-static: $(SNAME) install -d $(DESTDIR)$(LIBDIR) diff --git a/TODO b/TODO new file mode 100644 index 0000000..3120da8 --- /dev/null +++ b/TODO @@ -0,0 +1,3 @@ +- Implement packet creation/send/recv +- Implement callbacks +- Implement SRV record lookup diff --git a/config.mk b/config.mk index 8a70d53..2525823 100644 --- a/config.mk +++ b/config.mk @@ -5,6 +5,7 @@ INCLUDEDIR = $(PREFIX)/include LIBDIR = $(PREFIX)/lib BUILD_DIR = build +BUILD_DIR_TESTS = ../build/tests NAME = libumumble SNAME = $(NAME).a DNAME = $(NAME).so diff --git a/include/umumble/constants.h b/include/umumble/constants.h new file mode 100644 index 0000000..5dfded4 --- /dev/null +++ b/include/umumble/constants.h @@ -0,0 +1,78 @@ +#ifndef UMUMBLE_CONSTANTS_H +#define UMUMBLE_CONSTANTS_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +enum mumble_tcp_packet_type { + MUMBLE_TCP_PACKET_Version, + MUMBLE_TCP_PACKET_UDPTunnel, + MUMBLE_TCP_PACKET_Authenticate, + MUMBLE_TCP_PACKET_Ping, + MUMBLE_TCP_PACKET_Reject, + MUMBLE_TCP_PACKET_ServerSync, + MUMBLE_TCP_PACKET_ChannelRemove, + MUMBLE_TCP_PACKET_ChannelState, + MUMBLE_TCP_PACKET_UserRemove, + MUMBLE_TCP_PACKET_UserState, + MUMBLE_TCP_PACKET_BanList, + MUMBLE_TCP_PACKET_TextMessage, + MUMBLE_TCP_PACKET_PermissionDenied, + MUMBLE_TCP_PACKET_ACL, + MUMBLE_TCP_PACKET_QueryUsers, + MUMBLE_TCP_PACKET_CryptSetup, + MUMBLE_TCP_PACKET_ContextActionModify, + MUMBLE_TCP_PACKET_ContextAction, + MUMBLE_TCP_PACKET_UserList, + MUMBLE_TCP_PACKET_VoiceTarget, + MUMBLE_TCP_PACKET_PermissionQuery, + MUMBLE_TCP_PACKET_CodecVersion, + MUMBLE_TCP_PACKET_UserStats, + MUMBLE_TCP_PACKET_RequestBlob, + MUMBLE_TCP_PACKET_ServerConfig, + MUMBLE_TCP_PACKET_SuggestConfig, + MUMBLE_TCP_PACKET_PluginDataTransmission, +}; + +enum mumble_udp_packet_type { + MUMBLE_UDP_PACKET_Audio, + MUMBLE_UDP_PACKET_Ping +}; + +enum mumble_acl { + MUMBLE_ACL_None = 0, + MUMBLE_ACL_Write = 1, + MUMBLE_ACL_Traverse = 1 << 1, + MUMBLE_ACL_Enter = 1 << 2, + MUMBLE_ACL_Speak = 1 << 3, + MUMBLE_ACL_MuteDeafen = 1 << 4, + MUMBLE_ACL_Move = 1 << 5, + MUMBLE_ACL_MakeChannel = 1 << 6, + MUMBLE_ACL_LinkChannel = 1 << 7, + MUMBLE_ACL_Whisper = 1 << 8, + MUMBLE_ACL_TextMessage = 1 << 9, + MUMBLE_ACL_MakeTempChannel = 1 << 10, + MUMBLE_ACL_Listen = 1 << 11, + + // Root channel only + MUMBLE_ACL_Kick = 1 << 16, + MUMBLE_ACL_Ban = 1 << 17, + MUMBLE_ACL_Register = 1 << 18, + MUMBLE_ACL_SelfRegister = 1 << 19, + MUMBLE_ACL_ResetUserContent = 1 << 20 +}; + +enum mumble_ctx_status { + MUMBLE_STATUS_UNINITIALIZED = 0, + MUMBLE_STATUS_READY, + MUMBLE_STATUS_CONNECTING, + MUMBLE_STATUS_CONNECTED, + MUMBLE_STATUS_DISCONNECTED +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* UMUMBLE_CONSTANTS_H */ diff --git a/include/libumumble.h b/include/umumble/umumble.h index 43ba3ec..755be59 100644 --- a/include/libumumble.h +++ b/include/umumble/umumble.h @@ -1,23 +1,17 @@ -#ifndef LIBUMUMBLE_H -#define LIBUMUMBLE_H +#ifndef UMUMBLE_UMUMBLE_H +#define UMUMBLE_UMUMBLE_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ +#include "constants.h" + #include <uv.h> #include <tlsuv/tlsuv.h> -enum mumble_ctx_status { - UNINITIALIZED = 0, - READY, - CONNECTING, - CONNECTED, - DISCONNECTED -}; - -typedef struct mumble_ctx { - enum mumble_ctx_status status; +typedef struct mumble_ctx_s { + int status; int error; uv_loop_t uv_loop; uv_getaddrinfo_t uv_resolver; @@ -52,4 +46,4 @@ int mumble_run(mumble_ctx_t *ctx); } #endif /* __cplusplus */ -#endif /* LIBUMUMBLE_H */ +#endif /* UMUMBLE_UMUMBLE_H */ diff --git a/src/connection.c b/src/connection.c index c484163..2c2bfbd 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1,10 +1,10 @@ #include <stdlib.h> #include <assert.h> +#include <string.h> -#include <libumumble.h> +#include <umumble/umumble.h> #include <tlsuv/tlsuv.h> #include <uv.h> -#include "Mumble.pb.h" void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { buf->base = malloc(suggested_size); @@ -37,10 +37,10 @@ void on_read_cb(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) if (nread < 0) { if (nread != UV_EOF) { ctx->error = nread; - ctx->status = DISCONNECTED; + ctx->status = MUMBLE_STATUS_DISCONNECTED; } tlsuv_stream_close((tlsuv_stream_t *) client, on_close_cb); - ctx->status = DISCONNECTED; + ctx->status = MUMBLE_STATUS_DISCONNECTED; free(buf->base); free(client); return; @@ -62,11 +62,11 @@ void on_connect_cb(uv_connect_t *req, int status) if (status < 0) { ctx->error = status; - ctx->status = DISCONNECTED; + ctx->status = MUMBLE_STATUS_DISCONNECTED; tlsuv_stream_close((tlsuv_stream_t *) req->handle, on_close_cb); return; } - ctx->status = CONNECTED; + ctx->status = MUMBLE_STATUS_CONNECTED; tlsuv_stream_read(tls_stream, alloc_buffer, on_read_cb); @@ -89,7 +89,7 @@ void on_resolve_cb(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) assert(status >= 0); if (status < 0) { ctx->error = status; - ctx->status = DISCONNECTED; + ctx->status = MUMBLE_STATUS_DISCONNECTED; return; } diff --git a/src/ctx.c b/src/ctx.c index 35864d1..2612ffb 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -1,7 +1,7 @@ #include <assert.h> #include <string.h> -#include <libumumble.h> +#include <umumble/umumble.h> #include <uv.h> int mumble_ctx_init(mumble_ctx_t *ctx) @@ -19,7 +19,7 @@ int mumble_ctx_init(mumble_ctx_t *ctx) ctx->uv_connect_req.data = ctx; ctx->uv_tcp_socket.data = ctx; - ctx->status = READY; + ctx->status = MUMBLE_STATUS_READY; return 0; } diff --git a/src/message.c b/src/message.c new file mode 100644 index 0000000..8c066c2 --- /dev/null +++ b/src/message.c @@ -0,0 +1,15 @@ +#include <stdint.h> +#include <string.h> +#include <arpa/inet.h> + +static void mumble_packet_gen_header(uint8_t *buf, uint16_t type, uint32_t len) +{ + uint16_t type_be; + uint32_t len_be; + + type_be = htons(type); + len_be = htonl(len); + + memcpy(buf, &type_be, 2); + memcpy(buf+2, &len_be, 4); +} diff --git a/src/Mumble.proto b/src/proto/MumbleTCP.proto index c3a23f2..4a86e10 100644 --- a/src/Mumble.proto +++ b/src/proto/MumbleTCP.proto @@ -5,7 +5,7 @@ syntax = "proto2"; -package MumbleProto; +package MumbleTCP; option optimize_for = SPEED; diff --git a/src/proto/MumbleUDP.proto b/src/proto/MumbleUDP.proto new file mode 100644 index 0000000..4f27390 --- /dev/null +++ b/src/proto/MumbleUDP.proto @@ -0,0 +1,85 @@ +// Copyright 2022 The Mumble Developers. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file at the root of the +// Mumble source tree or at <https://www.mumble.info/LICENSE>. + +syntax = "proto3"; + +package MumbleUDP; + +option optimize_for = SPEED; + +message Audio { + oneof Header { + // When this audio is sent by the client to the server, this is set to the target of the audio data. This target + // is a number in the range [0, 2^{32} - 1], where 0 means "normal talking", 2^{5} - 1 means "server loopback" + // and all other targets are understood as shout/whisper targets that have previously been registered via a + // VoiceTarget message (via TCP). + uint32 target = 1; + // When this audio is sent by the server to the client, this indicates the context in which the audio has been sent. + // 0: Normal speech + // 1: Shout to channel + // 2: Whisper to user + // 3: Received via channel listener + uint32 context = 2; + }; + + // The session of the client (sender) this audio was originally sent from. This field is not required when sending + // audio to the server, but will always be set when receiving audio from the server. + uint32 sender_session = 3; + + // The number of the first contained audio frame (indicating the position of that frame in the overall audio stream) + uint64 frame_number = 4; + + // The actual voice data payload in the Opus format. + bytes opus_data = 5; + + // Optional positional data indicating the speaker's position in a virtual world (in meters). This "list" is really + // expected to be an array of size 3 containing the X, Y and Z coordinates of the position (in that order). + repeated float positional_data = 6; + + // A volume adjustment determined by the server for this audio packet. It is up to the client to apply this adjustment to + // the resulting audio (or not). Note: A value of 0 means that this field is unset. + float volume_adjustment = 7; + + // Note that we skip the field indices up to (including) 15 in order to have them available for future extensions of the + // protocol with fields that are encountered very often. The reason is that all field indices <= 15 require only a single + // byte of encoding overhead, whereas the once > 15 require (at least) two bytes. The reason lies in the Protobuf encoding + // scheme that uses 1 bit for a varint continuation flag, 3 bit to encode a field's type and the remaining 4 bit of the + // first byte are thus available for the field index. Therefore the first 2^4 = 16 field indices (aka values 0 to 15) can + // be encoded using only a single byte. For details see https://developers.google.com/protocol-buffers/docs/encoding + + // A flag indicating whether this audio packet represents the end of transmission for the current audio stream + bool is_terminator = 16; +} + +/** + * Ping message for checking UDP connectivity (and roundtrip ping) and potentially obtaining further server + * details (e.g. version). + */ +message Ping { + // Timestamp as encoded by the client. A server is not supposed to attempt to decode or modify this field. Therefore, + // clients may choose an arbitrary format for this timestamp (as long as it fits into a uint64 field). + uint64 timestamp = 1; + + // A flag set by the sending client, if it wants to obtain additional information about the server. + bool request_extended_information = 2; + + + // Below are the fields for the "additional information" that are filled out by the server on request. + + // The version of the server in the new version format. + // The new protobuf Ping packet introduced with 1.5 drops support for the legacy version format + // since both server and client have to support this new format. + // (See https://github.com/mumble-voip/mumble/issues/5827) + uint64 server_version_v2 = 3; + + // The amount of users currently connected to the server + uint32 user_count = 4; + + // The maximum amount of users permitted on this server + uint32 max_user_count = 5; + + // The maximum bandwidth each user is allowed to use for sending audio to the server + uint32 max_bandwidth_per_user = 6; +} diff --git a/tests/Makefile b/tests/Makefile index 95a146b..b6ee873 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,5 @@ include ../config.mk +BUILD_DIR = $(BUILD_DIR_TESTS) INCLUDES = -I../include SRC = $(shell find -type f -name '*.c') @@ -7,7 +8,7 @@ BIN = $(SRC:%.c=%) LDLIBS := -l:libumumble.a $(LDLIBS) LDFLAGS += -L.. -.PHONY: all +.PHONY: all clean all: $(BIN) diff --git a/tests/test.c b/tests/test.c index 1c673a0..848ec38 100644 --- a/tests/test.c +++ b/tests/test.c @@ -1,4 +1,4 @@ -#include <libumumble.h> +#include <umumble/umumble.h> int main(int argc, char *argv[]) { |