From 2a038579550489d387742112741b1e0e19f3a487 Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Wed, 24 Jul 2019 01:03:01 +0200 Subject: [PATCH] Fixed a crash and using properly the Nan::HandlerScropes in async callbacks --- native/CMakeLists.txt | 7 ++- native/create_symbols.sh | 37 +++++++++++ native/relink.sh | 2 + .../src/audio/codec/OpusConverter.cpp | 48 +++++--------- .../src/audio/js/AudioConsumer.cpp | 18 ++++-- .../src/audio/js/AudioFilter.cpp | 16 ++--- .../src/audio/js/AudioOutputStream.cpp | 17 ++--- .../src/audio/js/AudioPlayer.cpp | 4 +- .../src/audio/js/AudioRecorder.cpp | 4 +- .../src/connection/ServerConnection.cpp | 62 +++++++++++-------- .../src/connection/Socket.cpp | 8 +++ .../src/connection/audio/VoiceClient.cpp | 13 ++-- .../src/connection/audio/VoiceConnection.cpp | 12 ++-- .../src/connection/ft/FileTransferManager.cpp | 38 ++++++++---- native/serverconnection/src/logger.cpp | 4 +- native/serverconnection/test/js/main.ts | 20 +++++- 16 files changed, 201 insertions(+), 109 deletions(-) create mode 100755 native/create_symbols.sh diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index 2a57114..af4ea6f 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -24,6 +24,9 @@ function(setup_nodejs) set(NODEJS_URL "https://atom.io/download/atom-shell") set(NODEJS_VERSION "v5.0.6") + #set(NODEJS_URL "https://nodejs.org/download/release/") + #set(NODEJS_VERSION "v12.7.0") + find_package(NodeJS REQUIRED) set(NODEJS_NAN_DIR "node_modules/nan") @@ -49,7 +52,6 @@ function(setup_nodejs) set(NODEJS_INIT ${NODEJS_INIT} PARENT_SCOPE) include_directories("dist/ext_nan") - message("${NODEJS_INCLUDE_DIRS}") function(add_nodejs_module NAME) @@ -134,7 +136,10 @@ endif() setup_nodejs() if(NOT NODEJS_INCLUDE_DIRS OR NODEJS_INCLUDE_DIRS STREQUAL "") message(FATAL_ERROR "Failed to find node headers") +else() + message("Including NodeJS headers: ${NODEJS_INCLUDE_DIRS}") endif() +include_directories(${NODEJS_INCLUDE_DIRS}) function(build_update_installer) add_subdirectory(updater) diff --git a/native/create_symbols.sh b/native/create_symbols.sh new file mode 100755 index 0000000..34984b3 --- /dev/null +++ b/native/create_symbols.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +cd $(dirname $0) + +SYMBOL_ROOT="build/symbols" +BINARY_PATHS=("build/linux_x64/teaclient_connection.node" "build/linux_x64/teaclient_crash_handler.node" "build/linux_x64/teaclient_ppt.node" "build/exe/update-installer") + +echo "Created dump symbols!" +for file in ${BINARY_PATHS[@]}; do + if [[ ! -e ${file} ]]; then + echo "Missing binary ${file}. Skipping file" + continue + fi + + echo "Generating symbols for ${file}" + symbols="$(dump_syms ${file} 2>&1)" + if [[ $? -ne 0 ]]; then + echo "Failed to dump symbols for ${file}. Skipping file. Output:" + echo "${symbols}" + continue; + fi + + symbol_info=$(echo "${symbols}" | head -n1) + symbol_info_array=($symbol_info) + echo "Symbol dump id: ${symbol_info_array[3]}; Dump name: ${symbol_info_array[4]}" + symbol_path="${SYMBOL_ROOT}/${symbol_info_array[4]}/${symbol_info_array[3]}" + symbol_file="${symbol_info_array[4]}.sym" + echo "Saving symbols to ${symbol_path}/${symbol_file}" + mkdir -p ${symbol_path} + [[ $? -ne 0 ]] && { + echo "Failed to create target dump path! Skipping file" + continue + } + echo "${symbols}" > "${symbol_path}/${symbol_file}" +done +echo "All symbols have been created" + diff --git a/native/relink.sh b/native/relink.sh index 7d974f9..1c90ce8 100755 --- a/native/relink.sh +++ b/native/relink.sh @@ -30,3 +30,5 @@ if [[ ${machine} == "Linux" ]]; then rm teaclient_codec.node; ln -s ../../codec/cmake-build-debug/Debug/teaclient_codec.node rm teaclient_ppt.node; ln -s ../../ppt/cmake-build-debug/Debug/teaclient_ppt.node fi + +#/home/wolverindev/.config/TeaClient/crash_dumps/crash_dump_renderer_04a85069-9d30-48ec-e2fd5e9e-846c5305.dmp \ No newline at end of file diff --git a/native/serverconnection/src/audio/codec/OpusConverter.cpp b/native/serverconnection/src/audio/codec/OpusConverter.cpp index 1e979c9..d072aa1 100644 --- a/native/serverconnection/src/audio/codec/OpusConverter.cpp +++ b/native/serverconnection/src/audio/codec/OpusConverter.cpp @@ -29,37 +29,18 @@ bool OpusConverter::initialize(std::string &error, int application_type) { void OpusConverter::reset_encoder() { lock_guard lock(this->coder_lock); - string error; - bool flag_error = false; - if(!(flag_error |= !this->_finalize_encoder(error))) { - error = "finalize failed (" + error + ")"; - } - - if(!flag_error && !(flag_error |= !this->_initialize_encoder(error))) { - error = "initialize failed (" + error + ")"; - } - - if(flag_error) - log_warn(category::audio, tr("Failed to reset opus encoder: {}"), error); + auto result = opus_encoder_ctl(this->encoder, OPUS_RESET_STATE); + if(result != OPUS_OK) + log_warn(category::audio, tr("Failed to reset opus encoder. Opus result: {}"), result); } void OpusConverter::reset_decoder() { lock_guard lock(this->coder_lock); - string error; - bool flag_error = false; - - if(!(flag_error |= !this->_finalize_decoder(error))) { - error = "finalize failed (" + error + ")"; - } - - if(!flag_error && !(flag_error |= !this->_initialize_decoder(error))) { - error = "initialize failed (" + error + ")"; - } - - if(flag_error) - log_warn(category::audio, tr("Failed to reset opus decoder: {}"), error); + auto result = opus_decoder_ctl(this->decoder, OPUS_RESET_STATE); + if(result != OPUS_OK) + log_warn(category::audio, tr("Failed to reset opus decoder. Opus result: {}"), result); } @@ -85,6 +66,8 @@ ssize_t OpusConverter::encode(std::string &error, const void *source, void *targ } ssize_t OpusConverter::decode(std::string &error, const void *source, size_t source_length, void *target) { + lock_guard lock(this->coder_lock); + auto result = opus_decode_float(this->decoder, (uint8_t*) source, (opus_int32) source_length, (float*) target, (int) this->_frame_size, 0); if(result < OPUS_OK) { error = to_string(result) + "|" + opus_strerror(result); @@ -94,15 +77,16 @@ ssize_t OpusConverter::decode(std::string &error, const void *source, size_t sou } ssize_t OpusConverter::decode_lost(std::string &error, size_t packets) { - auto buffer = (float*) malloc(this->_frame_size * packets * this->_channels * sizeof(float)); - auto result = opus_decode_float(this->decoder, nullptr, 0, buffer, this->_frame_size * packets, false); - free(buffer); + lock_guard lock(this->coder_lock); - if(result < OPUS_OK) { - error = to_string(result) + "|" + opus_strerror(result); - return -1; + auto buffer = (float*) malloc(this->_frame_size * this->_channels * sizeof(float)); + while (packets-- > 0) { + auto result = opus_decode_float(this->decoder, nullptr, 0, buffer, this->_frame_size, false); + if(result < OPUS_OK) + log_warn(category::audio, tr("Opus decode lost resulted in error: {}"), result); } - return result; + free(buffer); + return 0; } size_t OpusConverter::expected_encoded_length(size_t sample_count) { diff --git a/native/serverconnection/src/audio/js/AudioConsumer.cpp b/native/serverconnection/src/audio/js/AudioConsumer.cpp index 005d6b3..e618fbf 100644 --- a/native/serverconnection/src/audio/js/AudioConsumer.cpp +++ b/native/serverconnection/src/audio/js/AudioConsumer.cpp @@ -61,6 +61,8 @@ void AudioConsumerWrapper::do_wrap(const v8::Local &obj) { this->Wrap(obj); this->_call_data = Nan::async_callback([&] { + Nan::HandleScope scope; + auto handle = this->handle(); v8::Local callback_function = handle->Get(Nan::New("callback_data").ToLocalChecked()); if(callback_function.IsEmpty() || callback_function->IsNullOrUndefined() || !callback_function->IsFunction()) { @@ -86,24 +88,28 @@ void AudioConsumerWrapper::do_wrap(const v8::Local &obj) { v8::Local argv[1]; argv[0] = js_fbuffer; - callback_function.As()->Call(Nan::Undefined(), 1, argv); + callback_function.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, argv); } }); this->_call_ended = Nan::async_callback([&]{ + Nan::HandleScope scope; + auto handle = this->handle(); v8::Local callback_function = handle->Get(Nan::New("callback_ended").ToLocalChecked()); if(callback_function.IsEmpty() || callback_function->IsNullOrUndefined() || !callback_function->IsFunction()) return; - callback_function.As()->Call(Nan::Undefined(), 0, nullptr); + callback_function.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); }); this->_call_started = Nan::async_callback([&]{ + Nan::HandleScope scope; + auto handle = this->handle(); v8::Local callback_function = handle->Get(Nan::New("callback_started").ToLocalChecked()); if(callback_function.IsEmpty() || callback_function->IsNullOrUndefined() || !callback_function->IsFunction()) return; - callback_function.As()->Call(Nan::Undefined(), 0, nullptr); + callback_function.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); }); Nan::Set(this->handle(), Nan::New("frame_size").ToLocalChecked(), Nan::New(this->_handle->frame_size)); @@ -248,7 +254,7 @@ NAN_METHOD(AudioConsumerWrapper::_unregister_filter) { return; } - auto consumer = ObjectWrap::Unwrap(info[0]->ToObject()); + auto consumer = ObjectWrap::Unwrap(info[0]->ToObject(Nan::GetCurrentContext()).ToLocalChecked()); handle->delete_filter(consumer); } @@ -265,7 +271,7 @@ NAN_METHOD(AudioConsumerWrapper::_create_filter_vad) { string error; auto filter = make_shared(consumer->channel_count,consumer->sample_rate,consumer->frame_size); - if(!filter->initialize(error, info[0]->Int32Value(), 2)) { + if(!filter->initialize(error, info[0]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0), 2)) { Nan::ThrowError(Nan::New("failed to initialize filter (" + error + ")").ToLocalChecked()); return; } @@ -286,7 +292,7 @@ NAN_METHOD(AudioConsumerWrapper::_create_filter_threshold) { string error; auto filter = make_shared(consumer->channel_count,consumer->sample_rate,consumer->frame_size); - if(!filter->initialize(error, info[0]->Int32Value(), 2)) { + if(!filter->initialize(error, info[0]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0), 2)) { Nan::ThrowError(Nan::New("failed to initialize filter (" + error + ")").ToLocalChecked()); return; } diff --git a/native/serverconnection/src/audio/js/AudioFilter.cpp b/native/serverconnection/src/audio/js/AudioFilter.cpp index a80f6a8..4b601b0 100644 --- a/native/serverconnection/src/audio/js/AudioFilter.cpp +++ b/native/serverconnection/src/audio/js/AudioFilter.cpp @@ -48,13 +48,15 @@ AudioFilterWrapper::AudioFilterWrapper(const std::string& name, const std::share auto threshold_filter = dynamic_pointer_cast(this->_filter); if(threshold_filter) { this->_call_analyzed = Nan::async_callback([&](float value) { + Nan::HandleScope scope; + if(!this->_callback_analyzed.IsEmpty()) { auto cb = Nan::New(this->_callback_analyzed); v8::Local argv[1]; argv[0] = Nan::New(value); - cb->Call(Nan::Undefined(), 1, argv); + cb->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, argv); } }); } @@ -132,9 +134,9 @@ NAN_METHOD(AudioFilterWrapper::_set_margin_frames) { auto vad_filter = dynamic_pointer_cast(handle->_filter); auto threshold_filter = dynamic_pointer_cast(handle->_filter); if(vad_filter) { - vad_filter->set_margin_frames(info[0]->Int32Value()); + vad_filter->set_margin_frames(info[0]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0)); } else if(threshold_filter) { - threshold_filter->set_margin_frames(info[0]->Int32Value()); + threshold_filter->set_margin_frames(info[0]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0)); } else { Nan::ThrowError("invalid handle"); return; @@ -176,7 +178,7 @@ NAN_METHOD(AudioFilterWrapper::_set_threshold) { return; } - filter->set_threshold(info[0]->Int32Value()); + filter->set_threshold(info[0]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0)); } NAN_METHOD(AudioFilterWrapper::_get_attack_smooth) { @@ -212,7 +214,7 @@ NAN_METHOD(AudioFilterWrapper::_set_attack_smooth) { return; } - filter->attack_smooth(info[0]->NumberValue()); + filter->attack_smooth(info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); } NAN_METHOD(AudioFilterWrapper::_get_release_smooth) { @@ -248,7 +250,7 @@ NAN_METHOD(AudioFilterWrapper::_set_release_smooth) { return; } - filter->release_smooth(info[0]->NumberValue()); + filter->release_smooth(info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); } NAN_METHOD(AudioFilterWrapper::_set_analyze_filter) { @@ -313,5 +315,5 @@ NAN_METHOD(AudioFilterWrapper::_set_consuming) { return; } - filter->set_consume_input(info[0]->BooleanValue()); + filter->set_consume_input(info[0]->BooleanValue(info.GetIsolate())); } \ No newline at end of file diff --git a/native/serverconnection/src/audio/js/AudioOutputStream.cpp b/native/serverconnection/src/audio/js/AudioOutputStream.cpp index 9e59712..5d31b07 100644 --- a/native/serverconnection/src/audio/js/AudioOutputStream.cpp +++ b/native/serverconnection/src/audio/js/AudioOutputStream.cpp @@ -74,16 +74,19 @@ void AudioOutputStreamWrapper::do_wrap(const v8::Local &obj) { if(this->_own_handle) { this->call_underflow = Nan::async_callback([&]{ + + Nan::HandleScope scope; auto handle = this->handle(); auto callback = Nan::Get(handle, Nan::New("callback_underflow").ToLocalChecked()).ToLocalChecked(); if(callback->IsFunction()) - callback.As()->Call(Nan::Undefined(), 0, nullptr); + callback.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); }); this->call_overflow = Nan::async_callback([&]{ + Nan::HandleScope scope; auto handle = this->handle(); auto callback = Nan::Get(handle, Nan::New("callback_overflow").ToLocalChecked()).ToLocalChecked(); if(callback->IsFunction()) - callback.As()->Call(Nan::Undefined(), 0, nullptr); + callback.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); }); this->_own_handle->on_overflow = [&](size_t){ this->call_overflow(); }; @@ -151,7 +154,7 @@ NAN_METHOD(AudioOutputStreamWrapper::_write_data) { return; } - auto interleaved = info[1]->BooleanValue(); + auto interleaved = info[1]->BooleanValue(info.GetIsolate()); auto js_buffer = info[0].As()->GetContents(); if(js_buffer.ByteLength() % (handle->channel_count * 4) != 0) { @@ -177,8 +180,8 @@ NAN_METHOD(AudioOutputStreamWrapper::_write_data_rated) { return; } - auto sample_rate = info[2]->NumberValue(); - auto interleaved = info[1]->BooleanValue(); + auto sample_rate = info[2]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0); + auto interleaved = info[1]->BooleanValue(info.GetIsolate()); auto js_buffer = info[0].As()->GetContents(); auto samples = js_buffer.ByteLength() / handle->channel_count / 4; @@ -249,7 +252,7 @@ NAN_METHOD(AudioOutputStreamWrapper::_set_buffer_latency) { return; } - handle->min_buffer = (size_t) ceil(handle->sample_rate * info[0]->NumberValue()); + handle->min_buffer = (size_t) ceil(handle->sample_rate * info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); } NAN_METHOD(AudioOutputStreamWrapper::_get_buffer_max_latency) { @@ -278,5 +281,5 @@ NAN_METHOD(AudioOutputStreamWrapper::_set_buffer_max_latency) { return; } - handle->max_latency = (size_t) ceil(handle->sample_rate * info[0]->NumberValue()); + handle->max_latency = (size_t) ceil(handle->sample_rate * info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); } \ No newline at end of file diff --git a/native/serverconnection/src/audio/js/AudioPlayer.cpp b/native/serverconnection/src/audio/js/AudioPlayer.cpp index f7b7504..3e4d3c1 100644 --- a/native/serverconnection/src/audio/js/AudioPlayer.cpp +++ b/native/serverconnection/src/audio/js/AudioPlayer.cpp @@ -67,7 +67,7 @@ NAN_METHOD(player::set_playback_device) { } std::string error; - if(!global_audio_output->open_device(error, info[0]->NumberValue())) { + if(!global_audio_output->open_device(error, info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0))) { Nan::ThrowError(Nan::New("failed to open device (" + error + ")").ToLocalChecked()); return; } @@ -109,5 +109,5 @@ NAN_METHOD(player::set_master_volume) { Nan::ThrowError("invalid arguments"); return; } - global_audio_output->set_volume(info[0]->NumberValue()); + global_audio_output->set_volume(info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); } \ No newline at end of file diff --git a/native/serverconnection/src/audio/js/AudioRecorder.cpp b/native/serverconnection/src/audio/js/AudioRecorder.cpp index da40c56..8e9ad61 100644 --- a/native/serverconnection/src/audio/js/AudioRecorder.cpp +++ b/native/serverconnection/src/audio/js/AudioRecorder.cpp @@ -131,7 +131,7 @@ NAN_METHOD(AudioRecorderWrapper::_set_device) { return; } - auto device_id = info[0]->Int32Value(); + auto device_id = info[0]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); string error; if(!input->open_device(error, device_id)) { @@ -201,6 +201,6 @@ NAN_METHOD(AudioRecorderWrapper::_delete_consumer) { return; } - auto consumer = ObjectWrap::Unwrap(info[0]->ToObject()); + auto consumer = ObjectWrap::Unwrap(info[0]->ToObject(Nan::GetCurrentContext()).ToLocalChecked()); handle->delete_consumer(consumer); } \ No newline at end of file diff --git a/native/serverconnection/src/connection/ServerConnection.cpp b/native/serverconnection/src/connection/ServerConnection.cpp index 40775b5..b0a9c01 100644 --- a/native/serverconnection/src/connection/ServerConnection.cpp +++ b/native/serverconnection/src/connection/ServerConnection.cpp @@ -92,12 +92,22 @@ void ServerConnection::initialize() { this->voice_connection->_ref = this->voice_connection; this->voice_connection->initialize_js_object(); - this->execute_pending_commands = Nan::async_callback([&]{ this->_execute_callback_commands(); }); - this->execute_pending_voice = Nan::async_callback([&]{ this->_execute_callback_voice(); }); - this->execute_callback_disconnect = Nan::async_callback([&](std::string reason){ this->_execute_callback_disconnect(reason); }); + this->execute_pending_commands = Nan::async_callback([&]{ + Nan::HandleScope scope; + this->_execute_callback_commands(); + }); + this->execute_pending_voice = Nan::async_callback([&]{ + Nan::HandleScope scope; + this->_execute_callback_voice(); + }); + this->execute_callback_disconnect = Nan::async_callback([&](std::string reason){ + Nan::HandleScope scope; + this->_execute_callback_disconnect(reason); + }); this->call_connect_result = Nan::async_callback([&](ErrorHandler::error_id error_id) { + Nan::HandleScope scope; /* lets update the server type */ { auto js_this = this->handle(); @@ -117,6 +127,7 @@ void ServerConnection::initialize() { this->call_disconnect_result = Nan::async_callback([&](ErrorHandler::error_id error_id) { + Nan::HandleScope scope; v8::Local argv[1]; argv[0] = Nan::New(error_id); @@ -188,7 +199,7 @@ NAN_METHOD(ServerConnection::connect) { return; } - v8::Local arguments = info[0]->ToObject(); + v8::Local arguments = info[0]->ToObject(Nan::GetCurrentContext()).ToLocalChecked(); if(!arguments->IsObject()) { Nan::ThrowError(tr("Invalid argument")); @@ -231,7 +242,7 @@ NAN_METHOD(ServerConnection::connect) { this->protocol_handler->reset(); if(identity_key->IsString()) { auto& identity = this->protocol_handler->get_identity_key(); - auto key = base64::decode(*Nan::Utf8String(identity_key->ToString())); + auto key = base64::decode(*Nan::Utf8String(identity_key->ToString(Nan::GetCurrentContext()).ToLocalChecked())); if(ecc_import((u_char*) key.data(), key.length(), &identity) != CRYPT_OK) { Nan::ThrowError(tr("failed to import identity")); return; @@ -256,7 +267,7 @@ NAN_METHOD(ServerConnection::connect) { hints.ai_family = AF_UNSPEC; - auto _remote_host = Nan::Utf8String(remote_host->ToString()); + auto _remote_host = Nan::Utf8String(remote_host->ToString(Nan::GetCurrentContext()).ToLocalChecked()); if(getaddrinfo(*_remote_host, nullptr, &hints, &result) != 0 || !result) { this->call_connect_result(this->errors.register_error(tr("failed to resolve hostname"))); return; @@ -267,9 +278,9 @@ NAN_METHOD(ServerConnection::connect) { } switch(remote_address.ss_family) { case AF_INET: - ((sockaddr_in*) &remote_address)->sin_port = htons(remote_port->Int32Value()); + ((sockaddr_in*) &remote_address)->sin_port = htons(remote_port->Int32Value(Nan::GetCurrentContext()).FromMaybe(0)); case AF_INET6: - ((sockaddr_in6*) &remote_address)->sin6_port = htons(remote_port->Int32Value()); + ((sockaddr_in6*) &remote_address)->sin6_port = htons(remote_port->Int32Value(Nan::GetCurrentContext()).FromMaybe(0)); default:break; } @@ -283,7 +294,7 @@ NAN_METHOD(ServerConnection::connect) { this->socket->on_data = [&](const pipes::buffer_view& buffer) { this->protocol_handler->progress_packet(buffer); }; - if(teamspeak->IsBoolean() && teamspeak->BooleanValue()) + if(teamspeak->IsBoolean() && teamspeak->BooleanValue(info.GetIsolate())) this->protocol_handler->server_type = server_type::TEAMSPEAK; this->protocol_handler->connect(); } @@ -333,7 +344,7 @@ NAN_METHOD(ServerConnection::error_message) { return; } - auto error = this->errors.get_message(info[0]->IntegerValue()); + auto error = this->errors.get_message(info[0]->IntegerValue(Nan::GetCurrentContext()).FromMaybe(0)); info.GetReturnValue().Set(Nan::New(error).ToLocalChecked()); } @@ -364,7 +375,7 @@ NAN_METHOD(ServerConnection::send_command) { } auto begin = chrono::system_clock::now(); - auto command = info[0]->ToString(); + auto command = info[0]->ToString(Nan::GetCurrentContext()).ToLocalChecked(); auto arguments = info[1].As(); auto switches = info[2].As(); @@ -376,20 +387,20 @@ NAN_METHOD(ServerConnection::send_command) { return; } - v8::Local properties = object->ToObject()->GetOwnPropertyNames(); + v8::Local properties = object->ToObject(Nan::GetCurrentContext()).ToLocalChecked()->GetOwnPropertyNames(Nan::GetCurrentContext()).ToLocalChecked(); for(uint32_t i = 0; i < properties->Length(); i++) { - auto key = properties->Get(i)->ToString(); - auto value = object->ToObject()->Get(key); + auto key = properties->Get(i)->ToString(Nan::GetCurrentContext()).ToLocalChecked(); + auto value = object->ToObject(Nan::GetCurrentContext()).ToLocalChecked()->Get(Nan::GetCurrentContext(), key).ToLocalChecked(); string key_string = *Nan::Utf8String(key); if(value->IsInt32()) - cmd[index][key_string] = value->Int32Value(); + cmd[index][key_string] = value->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); else if(value->IsNumber() || value->IsNumberObject()) - cmd[index][key_string] = _to_string(value->NumberValue()); /* requires our own conversation because node overrides stuff to 0,0000*/ + cmd[index][key_string] = _to_string(value->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); /* requires our own conversation because node overrides stuff to 0,0000*/ else if(value->IsString()) - cmd[index][key_string] = *Nan::Utf8String(value->ToString()); + cmd[index][key_string] = *Nan::Utf8String(value->ToString(Nan::GetCurrentContext()).ToLocalChecked()); else if(value->IsBoolean() || value->IsBooleanObject()) - cmd[index][key_string] = value->BooleanValue(); + cmd[index][key_string] = value->BooleanValue(info.GetIsolate()); else if(value->IsNullOrUndefined()) cmd[index][key_string] = ""; else { @@ -442,7 +453,7 @@ NAN_METHOD(ServerConnection::send_voice_data) { auto voice_data = info[0].As()->Buffer(); - this->send_voice_data(voice_data->GetContents().Data(), voice_data->GetContents().ByteLength(), (uint8_t) info[1]->Int32Value(), info[2]->BooleanValue()); + this->send_voice_data(voice_data->GetContents().Data(), voice_data->GetContents().ByteLength(), (uint8_t) info[1]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0), info[2]->BooleanValue(info.GetIsolate())); } @@ -463,9 +474,9 @@ NAN_METHOD(ServerConnection::send_voice_data_raw) { return; } - auto channels = info[1]->Int32Value(); - auto sample_rate = info[2]->Int32Value(); - auto flag_head = info[2]->BooleanValue(); + auto channels = info[1]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); + auto sample_rate = info[2]->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); + auto flag_head = info[2]->BooleanValue(info.GetIsolate()); auto voice_data = info[0].As()->Buffer(); auto vs = this->voice_connection->voice_sender(); @@ -488,6 +499,7 @@ void ServerConnection::send_voice_data(const void *buffer, size_t buffer_length, if(head) /* head packet */ packet->enable_flag(ts::protocol::PacketFlag::Compressed); +#define FUZZ_VOICE #ifdef FUZZ_VOICE if((rand() % 10) < 2) { log_info(category::connection, tr("Dropping voice packet")); @@ -572,7 +584,7 @@ void ServerConnection::_execute_callback_commands() { } arguments[2] = switched; - callback->Call(Nan::Undefined(), 3, arguments); + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 3, arguments); } } @@ -614,7 +626,7 @@ void ServerConnection::_execute_callback_voice() { arguments[2] = Nan::New(next_packet->codec_id); arguments[3] = Nan::New(next_packet->flag_head); arguments[4] = Nan::New(next_packet->packet_id); - callback->Call(Nan::Undefined(), 5, arguments); + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 5, arguments); } } @@ -627,6 +639,6 @@ void ServerConnection::_execute_callback_disconnect(const std::string &reason) { v8::Local arguments[1]; arguments[0] = Nan::New(reason).ToLocalChecked(); - callback->Call(Nan::Undefined(), 1, arguments); + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, arguments); } \ No newline at end of file diff --git a/native/serverconnection/src/connection/Socket.cpp b/native/serverconnection/src/connection/Socket.cpp index fa1bc7e..558c200 100644 --- a/native/serverconnection/src/connection/Socket.cpp +++ b/native/serverconnection/src/connection/Socket.cpp @@ -10,6 +10,7 @@ typedef int socklen_t; #else #include + #include #endif using namespace std; @@ -33,6 +34,13 @@ bool UDPSocket::initialize() { return false; } + /* + * TODO: Make configurable + */ + //uint8_t value = IPTOS_DSCP_EF; + //if(setsockopt(this->file_descriptor, IPPROTO_IP, IP_TOS, &value, sizeof(value)) < 0) + // log_warn(category::connection, "Failed to set TOS high priority on socket"); + this->io_base = event_base_new(); if(!this->io_base) { /* may too many file descriptors already open */ this->finalize(); diff --git a/native/serverconnection/src/connection/audio/VoiceClient.cpp b/native/serverconnection/src/connection/audio/VoiceClient.cpp index 22da930..9b44e74 100644 --- a/native/serverconnection/src/connection/audio/VoiceClient.cpp +++ b/native/serverconnection/src/connection/audio/VoiceClient.cpp @@ -73,7 +73,10 @@ void VoiceClientWrap::do_wrap(const v8::Local &object) { Nan::Set(object, Nan::New("client_id").ToLocalChecked(), Nan::New(handle->client_id())); handle->on_state_changed = [&]{ this->call_state_changed(); }; - this->call_state_changed = Nan::async_callback([&]{ this->_call_state_changed(); }); + this->call_state_changed = Nan::async_callback([&]{ + Nan::HandleScope scope; + this->_call_state_changed(); + }); } void VoiceClientWrap::_call_state_changed() { @@ -95,12 +98,12 @@ void VoiceClientWrap::_call_state_changed() { if(call_playback_callback) { auto callback = Nan::Get(this->handle(), Nan::New("callback_playback").ToLocalChecked()).ToLocalChecked(); if(callback->IsFunction()) - callback.As()->Call(Nan::Undefined(), 0, nullptr); + callback.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); } if(call_stopped_callback) { auto callback = Nan::Get(this->handle(), Nan::New("callback_stopped").ToLocalChecked()).ToLocalChecked(); if(callback->IsFunction()) - callback.As()->Call(Nan::Undefined(), 0, nullptr); + callback.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); } auto callback = Nan::Get(this->handle(), Nan::New("callback_state_changed").ToLocalChecked()).ToLocalChecked(); @@ -108,7 +111,7 @@ void VoiceClientWrap::_call_state_changed() { v8::Local argv[1] = { Nan::New(state) }; - callback.As()->Call(Nan::Undefined(), 1, argv); + callback.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, argv); } } @@ -157,7 +160,7 @@ NAN_METHOD(VoiceClientWrap::_set_volume) { return; } - handle->set_volume(info[0]->NumberValue()); + handle->set_volume(info[0]->NumberValue(Nan::GetCurrentContext()).FromMaybe(0)); } NAN_METHOD(VoiceClientWrap::_abort_replay) { auto client = ObjectWrap::Unwrap(info.Holder()); diff --git a/native/serverconnection/src/connection/audio/VoiceConnection.cpp b/native/serverconnection/src/connection/audio/VoiceConnection.cpp index b3e9494..28519a9 100644 --- a/native/serverconnection/src/connection/audio/VoiceConnection.cpp +++ b/native/serverconnection/src/connection/audio/VoiceConnection.cpp @@ -61,7 +61,7 @@ NAN_METHOD(VoiceConnectionWrap::_encoding_supported) { Nan::ThrowError("invalid argument count"); return; } - auto codec = info[0]->Uint32Value(); + auto codec = info[0]->Uint32Value(Nan::GetCurrentContext()).FromMaybe(0); info.GetReturnValue().Set(codec >= 4 && codec <= 5); /* ignore SPEX currently :/ */ } @@ -71,7 +71,7 @@ NAN_METHOD(VoiceConnectionWrap::_decoding_supported) { Nan::ThrowError("invalid argument count"); return; } - auto codec = info[0]->Uint32Value(); + auto codec = info[0]->Uint32Value(Nan::GetCurrentContext()).FromMaybe(0); info.GetReturnValue().Set(codec >= 4 && codec <= 5); /* ignore SPEX currently :/ */ } @@ -85,7 +85,7 @@ NAN_METHOD(VoiceConnectionWrap::register_client) { Nan::ThrowError("invalid argument count"); return; } - auto id = info[0]->Uint32Value(); + auto id = info[0]->Uint32Value(Nan::GetCurrentContext()).FromMaybe(0); auto handle = this->handle.lock(); if(!handle) { Nan::ThrowError("handle has been deallocated"); @@ -131,7 +131,7 @@ NAN_METHOD(VoiceConnectionWrap::unregister_client) { Nan::ThrowError("invalid argument count"); return; } - auto id = info[0]->Uint32Value(); + auto id = info[0]->Uint32Value(Nan::GetCurrentContext()).FromMaybe(0); auto handle = this->handle.lock(); if(!handle) { Nan::ThrowError("handle has been deallocated"); @@ -180,8 +180,8 @@ NAN_METHOD(VoiceConnectionWrap::set_audio_source) { this->release_recorder(); if(!info[0]->IsNullOrUndefined()) { - this->_voice_recoder_ptr = ObjectWrap::Unwrap(info[0]->ToObject()); - this->_voice_recoder_handle.Reset(info[0]->ToObject()); + this->_voice_recoder_ptr = ObjectWrap::Unwrap(info[0]->ToObject(Nan::GetCurrentContext()).ToLocalChecked()); + this->_voice_recoder_handle.Reset(info[0]->ToObject(Nan::GetCurrentContext()).ToLocalChecked()); auto native_consumer = this->_voice_recoder_ptr->native_consumer(); diff --git a/native/serverconnection/src/connection/ft/FileTransferManager.cpp b/native/serverconnection/src/connection/ft/FileTransferManager.cpp index 4552565..bd0e138 100644 --- a/native/serverconnection/src/connection/ft/FileTransferManager.cpp +++ b/native/serverconnection/src/connection/ft/FileTransferManager.cpp @@ -7,6 +7,7 @@ #ifndef WIN32 #include + #include #else #include #define SOCK_NONBLOCK (0) @@ -546,6 +547,7 @@ void FileTransferManager::remove_transfer(tc::ft::Transfer *transfer) { } #ifdef NODEJS_API + NAN_MODULE_INIT(JSTransfer::Init) { auto klass = Nan::New(JSTransfer::NewInstance); klass->SetClassName(Nan::New("JSTransfer").ToLocalChecked()); @@ -569,7 +571,7 @@ NAN_METHOD(JSTransfer::NewInstance) { * server_transfer_id: number; * object: HandledTransferObject; */ - auto options = info[0]->ToObject(); + auto options = info[0]->ToObject(Nan::GetCurrentContext()).ToLocalChecked(); v8::Local key = options->Get(Nan::New("transfer_key").ToLocalChecked()).As(); v8::Local client_transfer_id = options->Get(Nan::New("client_transfer_id").ToLocalChecked()).As(); v8::Local server_transfer_id = options->Get(Nan::New("server_transfer_id").ToLocalChecked()).As(); @@ -598,10 +600,10 @@ NAN_METHOD(JSTransfer::NewInstance) { auto t_options = make_unique(); t_options->transfer_key = *Nan::Utf8String(key); - t_options->client_transfer_id = client_transfer_id->Int32Value(); - t_options->server_transfer_id = server_transfer_id->Int32Value(); + t_options->client_transfer_id = client_transfer_id->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); + t_options->server_transfer_id = server_transfer_id->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); t_options->remote_address = *Nan::Utf8String(remote_address); - t_options->remote_port = remote_port->Int32Value(); + t_options->remote_port = remote_port->Int32Value(Nan::GetCurrentContext()).FromMaybe(0); string error; auto transfer = transfer_manager->register_transfer(error, transfer_object, move(t_options)); @@ -635,10 +637,22 @@ NAN_METHOD(JSTransfer::NewInstance) { } JSTransfer::JSTransfer(std::shared_ptr transfer) : _transfer(move(transfer)) { - this->call_failed = Nan::async_callback([&](std::string error) { this->callback_failed(error); }); - this->call_finished = Nan::async_callback([&](bool f) { this->callback_finished(f); }); - this->call_start = Nan::async_callback([&] { this->callback_start(); }); - this->call_progress = Nan::async_callback([&](uint64_t a, uint64_t b) { this->callback_progress(a, b); }); + this->call_failed = Nan::async_callback([&](std::string error) { + Nan::HandleScope scope; + this->callback_failed(error); + }); + this->call_finished = Nan::async_callback([&](bool f) { + Nan::HandleScope scope; + this->callback_finished(f); + }); + this->call_start = Nan::async_callback([&] { + Nan::HandleScope scope; + this->callback_start(); + }); + this->call_progress = Nan::async_callback([&](uint64_t a, uint64_t b) { + Nan::HandleScope scope; + this->callback_progress(a, b); + }); this->_transfer->callback_failed = [&](std::string error) { this->call_failed(std::forward(error)); }; this->_transfer->callback_finished = [&](bool f) { this->call_finished(std::forward(f)); }; @@ -689,7 +703,7 @@ void JSTransfer::callback_finished(bool flag) { v8::Local arguments[1]; arguments[0] = Nan::New(flag); - callback->Call(Nan::Undefined(), 1, arguments); + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, arguments); } void JSTransfer::callback_start() { @@ -697,7 +711,7 @@ void JSTransfer::callback_start() { if(callback.IsEmpty() || !callback->IsFunction()) return; - callback->Call(Nan::Undefined(), 0, nullptr); + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 0, nullptr); } void JSTransfer::callback_progress(uint64_t a, uint64_t b) { @@ -708,7 +722,7 @@ void JSTransfer::callback_progress(uint64_t a, uint64_t b) { v8::Local arguments[2]; arguments[0] = Nan::New(a); arguments[1] = Nan::New(b); - callback->Call(Nan::Undefined(), 2, arguments); + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 2, arguments); } void JSTransfer::callback_failed(std::string error) { @@ -722,6 +736,6 @@ void JSTransfer::callback_failed(std::string error) { v8::Local arguments[1]; arguments[0] = Nan::New(error).ToLocalChecked(); - callback->Call(Nan::Undefined(), 1, arguments); + callback->Call(Nan::GetCurrentContext(), Nan::Undefined(), 1, arguments); } #endif \ No newline at end of file diff --git a/native/serverconnection/src/logger.cpp b/native/serverconnection/src/logger.cpp index 6cf53f4..7ae6faf 100644 --- a/native/serverconnection/src/logger.cpp +++ b/native/serverconnection/src/logger.cpp @@ -54,6 +54,8 @@ inline v8::Local get_logger_method() { void logger::initialize_node() { log_messages_callback = Nan::async_callback([]{ + Nan::HandleScope scope; + auto isolate = Nan::GetCurrentContext()->GetIsolate(); v8::Local logger_method = get_logger_method(); @@ -74,7 +76,7 @@ void logger::initialize_node() { arguments[1] = Nan::New(entry->level); arguments[2] = v8::String::NewExternalOneByte(isolate, new StdExternalStringResourceBase(entry->message)).ToLocalChecked(); - logger_method.As()->Call(Nan::Undefined(), 3, arguments); + logger_method.As()->Call(Nan::GetCurrentContext(), Nan::Undefined(), 3, arguments); } else { std::cout << "Failed to log message! Invalid method!" << std::endl; } diff --git a/native/serverconnection/test/js/main.ts b/native/serverconnection/test/js/main.ts index 136728e..bd9106b 100644 --- a/native/serverconnection/test/js/main.ts +++ b/native/serverconnection/test/js/main.ts @@ -3,7 +3,11 @@ module.paths.push("../../build/linux_x64"); module.paths.push("../../build/win32_64"); import * as fs from "fs"; + +const original_require = require; +require = module => original_require("/home/wolverindev/TeaSpeak-Client/client/native/build/linux_x64/" + module + ".node"); import * as handle from "teaclient_connection"; +require = original_require; const connection_list = []; const connection = handle.spawn_server_connection(); @@ -13,8 +17,8 @@ console.dir(handle); console.log("Query devices..."); console.log("Devices: %o", handle.audio.available_devices()); console.log("Current playback device: %o", handle.audio.playback.current_device()); -handle.audio.playback.set_device(15); -console.log("Current playback device: %o", handle.audio.playback.current_device()); +//handle.audio.playback.set_device(14); +//console.log("Current playback device: %o", handle.audio.playback.current_device()); const stream = handle.audio.playback.create_stream(); console.log("Own stream: %o", stream); @@ -24,7 +28,17 @@ console.log("Own stream: %o", stream); const recorder = handle.audio.record.create_recorder(); console.log("Have device: %o", recorder); console.log("Device: %o", recorder.get_device()); -recorder.set_device(15); +if(recorder.get_device() == -1) { + console.log("Looking for devices"); + for(const device of handle.audio.available_devices()) { + if(!device.input_supported) + continue; + if(device.name != "pulse") + continue; + console.log("Found pulse at %o", device.device_index); + recorder.set_device(device.device_index); + } +} console.log("Device: %o", recorder.get_device()); recorder.start(); console.log("Started: %o", recorder.started());