jfieldID get_field_id(JNIEnv *env, jclass clazz, const char *name, const char *signature) { jfieldID res = env->GetFieldID(clazz, name, signature); if (!res) { fatal_error(env, PSLICE() << "Can't find field [" << name << "] with signature [" << signature << "]"); } return res; }
void init_vars(JNIEnv *env, const char *td_api_java_package) { BooleanClass = get_jclass(env, "java/lang/Boolean"); IntegerClass = get_jclass(env, "java/lang/Integer"); LongClass = get_jclass(env, "java/lang/Long"); DoubleClass = get_jclass(env, "java/lang/Double"); StringClass = get_jclass(env, "java/lang/String"); ObjectClass = get_jclass(env, (PSLICE() << td_api_java_package << "/TdApi$Object").c_str()); ArrayKeyboardButtonClass = get_jclass(env, (PSLICE() << "[L" << td_api_java_package << "/TdApi$KeyboardButton;").c_str()); ArrayInlineKeyboardButtonClass = get_jclass(env, (PSLICE() << "[L" << td_api_java_package << "/TdApi$InlineKeyboardButton;").c_str()); GetConstructorID = get_method_id(env, ObjectClass, "getConstructor", "()I"); BooleanGetValueMethodID = get_method_id(env, BooleanClass, "booleanValue", "()Z"); IntegerGetValueMethodID = get_method_id(env, IntegerClass, "intValue", "()I"); LongGetValueMethodID = get_method_id(env, LongClass, "longValue", "()J"); DoubleGetValueMethodID = get_method_id(env, DoubleClass, "doubleValue", "()D"); }
void NetQueryDispatcher::dispatch(NetQueryPtr net_query) { net_query->debug("dispatch"); if (stop_flag_.load(std::memory_order_relaxed)) { // Set error to avoid warning // No need to send result somewhere, it probably will be ignored anyway net_query->set_error(Status::Error(500, "Internal Server Error: closing")); net_query->clear(); net_query.reset(); // G()->net_query_creator().release(std::move(net_query)); return; } if (net_query->is_ready()) { if (net_query->is_error()) { auto code = net_query->error().code(); if (code == 303) { try_fix_migrate(net_query); } else if (code == NetQuery::Resend) { net_query->resend(); } else if (code < 0 || code == 500 || code == 420) { net_query->debug("sent to NetQueryDelayer"); return send_closure(delayer_, &NetQueryDelayer::delay, std::move(net_query)); } } } if (!net_query->is_ready()) { if (net_query->dispatch_ttl == 0) { net_query->set_error(Status::Error("DispatchTtlError")); } } auto dest_dc_id = net_query->dc_id(); if (dest_dc_id.is_main()) { dest_dc_id = DcId::internal(main_dc_id_.load(std::memory_order_relaxed)); } if (!net_query->is_ready() && wait_dc_init(dest_dc_id, true).is_error()) { net_query->set_error(Status::Error(PSLICE() << "No such dc " << dest_dc_id)); } if (net_query->is_ready()) { auto callback = net_query->move_callback(); if (callback.empty()) { net_query->debug("sent to td (no callback)"); send_closure(G()->td(), &NetQueryCallback::on_result, std::move(net_query)); } else { net_query->debug("sent to callback", true); send_closure(std::move(callback), &NetQueryCallback::on_result, std::move(net_query)); } return; } if (net_query->dispatch_ttl > 0) { net_query->dispatch_ttl--; } size_t dc_pos = static_cast<size_t>(dest_dc_id.get_raw_id() - 1); CHECK(dc_pos < dcs_.size()); switch (net_query->type()) { case NetQuery::Type::Common: net_query->debug(PSTRING() << "sent to main session multi proxy " << dest_dc_id); send_closure_later(dcs_[dc_pos].main_session_, &SessionMultiProxy::send, std::move(net_query)); break; case NetQuery::Type::Upload: net_query->debug(PSTRING() << "sent to upload session multi proxy " << dest_dc_id); send_closure_later(dcs_[dc_pos].upload_session_, &SessionMultiProxy::send, std::move(net_query)); break; case NetQuery::Type::Download: net_query->debug(PSTRING() << "sent to download session multi proxy " << dest_dc_id); send_closure_later(dcs_[dc_pos].download_session_, &SessionMultiProxy::send, std::move(net_query)); break; case NetQuery::Type::DownloadSmall: net_query->debug(PSTRING() << "sent to download small session multi proxy " << dest_dc_id); send_closure_later(dcs_[dc_pos].download_small_session_, &SessionMultiProxy::send, std::move(net_query)); break; } }
Status NetQueryDispatcher::wait_dc_init(DcId dc_id, bool force) { // TODO: optimize if (!dc_id.is_exact()) { return Status::Error("Not exact DC"); } size_t pos = static_cast<size_t>(dc_id.get_raw_id() - 1); if (pos >= dcs_.size()) { return Status::Error("Too big DC id"); } auto &dc = dcs_[pos]; bool should_init = false; if (!dc.is_valid_) { if (!force) { return Status::Error("Invalid DC"); } bool expected = false; should_init = dc.is_valid_.compare_exchange_strong(expected, true, std::memory_order_seq_cst, std::memory_order_seq_cst); } if (should_init) { std::lock_guard<std::mutex> guard(main_dc_id_mutex_); if (stop_flag_.load(std::memory_order_relaxed)) { return Status::Error("Closing"); } // init dc decltype(common_public_rsa_key_) public_rsa_key; bool is_cdn = false; if (dc_id.is_internal()) { public_rsa_key = common_public_rsa_key_; } else { public_rsa_key = std::make_shared<PublicRsaKeyShared>(dc_id); send_closure_later(public_rsa_key_watchdog_, &PublicRsaKeyWatchdog::add_public_rsa_key, public_rsa_key); is_cdn = true; } auto auth_data = AuthDataShared::create(dc_id, std::move(public_rsa_key), td_guard_); int32 session_count = get_session_count(); bool use_pfs = get_use_pfs(); int32 slow_net_scheduler_id = G()->get_slow_net_scheduler_id(); auto raw_dc_id = dc_id.get_raw_id(); dc.main_session_ = create_actor<SessionMultiProxy>(PSLICE() << "SessionMultiProxy:" << raw_dc_id << ":main", session_count, auth_data, raw_dc_id == main_dc_id_, use_pfs || (session_count > 1), false, false, is_cdn); dc.upload_session_ = create_actor_on_scheduler<SessionMultiProxy>( PSLICE() << "SessionMultiProxy:" << raw_dc_id << ":upload", slow_net_scheduler_id, raw_dc_id != 2 && raw_dc_id != 4 ? 8 : 4, auth_data, false, use_pfs || (session_count > 1), false, true, is_cdn); dc.download_session_ = create_actor_on_scheduler<SessionMultiProxy>( PSLICE() << "SessionMultiProxy:" << raw_dc_id << ":download", slow_net_scheduler_id, 1, auth_data, false, use_pfs, true, true, is_cdn); dc.download_small_session_ = create_actor_on_scheduler<SessionMultiProxy>( PSLICE() << "SessionMultiProxy:" << raw_dc_id << ":download_small", slow_net_scheduler_id, 1, auth_data, false, use_pfs, true, true, is_cdn); dc.is_inited_ = true; if (dc_id.is_internal()) { send_closure_later(dc_auth_manager_, &DcAuthManager::add_dc, std::move(auth_data)); } } else { while (!dc.is_inited_) { if (stop_flag_.load(std::memory_order_relaxed)) { return Status::Error("Closing"); } #if !TD_THREAD_UNSUPPORTED td::this_thread::yield(); #endif } } return Status::OK(); }
void ConfigShared::set_option_string(Slice name, Slice value) { if (set_option(name, PSLICE() << "S" << value)) { on_option_updated(name); } }
void ConfigShared::set_option_integer(Slice name, int32 value) { if (set_option(name, PSLICE() << "I" << value)) { on_option_updated(name); } }
void register_native_method(JNIEnv *env, jclass clazz, std::string name, std::string signature, void *function_ptr) { JNINativeMethod native_method{&name[0], &signature[0], function_ptr}; if (env->RegisterNatives(clazz, &native_method, 1) != 0) { fatal_error(env, PSLICE() << "RegisterNatives failed for " << name << " with signature " << signature); } }
Result<SslFd> SslFd::init(SocketFd fd, CSlice host, CSlice cert_file, VerifyPeer verify_peer) { #if TD_WINDOWS return Status::Error("TODO"); #else static bool init_openssl = [] { #if OPENSSL_VERSION_NUMBER >= 0x10100000L return OPENSSL_init_ssl(0, nullptr) != 0; #else OpenSSL_add_all_algorithms(); SSL_load_error_strings(); return OpenSSL_add_ssl_algorithms() != 0; #endif }(); CHECK(init_openssl); openssl_clear_errors("Before SslFd::init"); CHECK(!fd.empty()); auto ssl_method = #if OPENSSL_VERSION_NUMBER >= 0x10100000L TLS_client_method(); #else SSLv23_client_method(); #endif if (ssl_method == nullptr) { return create_openssl_error(-6, "Failed to create an SSL client method"); } auto ssl_ctx = SSL_CTX_new(ssl_method); if (ssl_ctx == nullptr) { return create_openssl_error(-7, "Failed to create an SSL context"); } auto ssl_ctx_guard = ScopeExit() + [&]() { SSL_CTX_free(ssl_ctx); }; long options = 0; #ifdef SSL_OP_NO_SSLv2 options |= SSL_OP_NO_SSLv2; #endif #ifdef SSL_OP_NO_SSLv3 options |= SSL_OP_NO_SSLv3; #endif SSL_CTX_set_options(ssl_ctx, options); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE); if (cert_file.empty()) { SSL_CTX_set_default_verify_paths(ssl_ctx); } else { if (SSL_CTX_load_verify_locations(ssl_ctx, cert_file.c_str(), nullptr) == 0) { return create_openssl_error(-8, "Failed to set custom cert file"); } } if (VERIFY_PEER && verify_peer == VerifyPeer::On) { SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, verify_callback); if (VERIFY_DEPTH != -1) { SSL_CTX_set_verify_depth(ssl_ctx, VERIFY_DEPTH); } } else { SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, nullptr); } // TODO(now): cipher list string cipher_list; if (SSL_CTX_set_cipher_list(ssl_ctx, cipher_list.empty() ? "DEFAULT" : cipher_list.c_str()) == 0) { return create_openssl_error(-9, PSLICE("Failed to set cipher list \"%s\"", cipher_list.c_str())); } auto ssl_handle = SSL_new(ssl_ctx); if (ssl_handle == nullptr) { return create_openssl_error(-13, "Failed to create an SSL handle"); } auto ssl_handle_guard = ScopeExit() + [&]() { do_ssl_shutdown(ssl_handle); SSL_free(ssl_handle); }; #if OPENSSL_VERSION_NUMBER >= 0x10002000L X509_VERIFY_PARAM *param = SSL_get0_param(ssl_handle); /* Enable automatic hostname checks */ // TODO: X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS X509_VERIFY_PARAM_set_hostflags(param, 0); X509_VERIFY_PARAM_set1_host(param, host.c_str(), 0); #else #warning DANGEROUS! HTTPS HOST WILL NOT BE CHECKED. INSTALL OPENSSL >= 1.0.2 OR IMPLEMENT HTTPS HOST CHECK MANUALLY #endif if (!SSL_set_fd(ssl_handle, fd.get_fd().get_native_fd())) { return create_openssl_error(-14, "Failed to set fd"); } #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) auto host_str = host.str(); SSL_set_tlsext_host_name(ssl_handle, MutableCSlice(host_str).begin()); #endif SSL_set_connect_state(ssl_handle); ssl_ctx_guard.dismiss(); ssl_handle_guard.dismiss(); return SslFd(std::move(fd), ssl_handle, ssl_ctx); #endif }