diff --git a/panda/src/downloader/config_downloader.cxx b/panda/src/downloader/config_downloader.cxx index 8fd7129998..a129727bcf 100644 --- a/panda/src/downloader/config_downloader.cxx +++ b/panda/src/downloader/config_downloader.cxx @@ -62,14 +62,6 @@ ConfigVariableDouble extractor_frequency ConfigVariableInt patcher_buffer_size ("patcher-buffer-size", 4096); -ConfigVariableBool early_random_seed -("early-random-seed", true, - PRC_DESC("Configure this true (the default) to compute the SSL random seed " - "early on in the application (specifically, when the first " - "HTTPClient is created), or false to defer this until it is actually " - "needed, causing a delay the first time a https connection is " - "attempted.")); - ConfigVariableBool verify_ssl ("verify-ssl", true, PRC_DESC("Configure this true (the default) to insist on verifying all SSL " @@ -156,9 +148,50 @@ ConfigVariableList http_username "If the server or realm is empty, they will match anything.")); ConfigureFn(config_downloader) { + init_libdownloader(); +} + +//////////////////////////////////////////////////////////////////// +// Function: init_libdownloader +// Description: Initializes the library. This must be called at +// least once before any of the functions or classes in +// this library can be used. Normally it will be +// called by the static initializers and need not be +// called explicitly, but special cases exist. +//////////////////////////////////////////////////////////////////// +void +init_libdownloader() { + static bool initialized = false; + if (initialized) { + return; + } + initialized = true; + #ifdef HAVE_SSL HTTPChannel::init_type(); + // We need to define this here, rather than above, to guarantee that + // it has been initialized by the time we check it. + ConfigVariableBool early_random_seed + ("early-random-seed", false, + PRC_DESC("Configure this true to compute the SSL random seed " + "early on in the application (specifically, when the libpandaexpress " + "library is loaded), or false to defer this until it is actually " + "needed (which will be the first time you open an https connection " + "or otherwise use encryption services). You can also call " + "HTTPClient::initialize_ssl() to " + "do this when you are ready. The issue is that on Windows, " + "OpenSSL will attempt to " + "randomize its seed by crawling through the entire heap of " + "allocated memory, which can be extremely large in a Panda " + "application, especially if you have already opened a window and " + "started rendering; and so this can take as much as 30 seconds " + "or more. For this reason it is best to initialize the random " + "seed at startup, when the application is still very small.")); + if (early_random_seed) { + HTTPClient::init_random_seed(); + } + PandaSystem *ps = PandaSystem::get_global_ptr(); ps->add_system("OpenSSL"); #endif diff --git a/panda/src/downloader/config_downloader.h b/panda/src/downloader/config_downloader.h index 1c870110aa..9495517149 100644 --- a/panda/src/downloader/config_downloader.h +++ b/panda/src/downloader/config_downloader.h @@ -46,7 +46,6 @@ extern ConfigVariableDouble extractor_frequency; extern ConfigVariableInt patcher_buffer_size; -extern ConfigVariableBool early_random_seed; extern ConfigVariableBool verify_ssl; extern ConfigVariableString ssl_cipher_list; extern ConfigVariableList expected_ssl_server; @@ -64,4 +63,6 @@ extern ConfigVariableFilename http_client_certificate_filename; extern ConfigVariableString http_client_certificate_passphrase; extern ConfigVariableList http_username; +extern EXPCL_PANDAEXPRESS void init_libdownloader(); + #endif diff --git a/panda/src/downloader/httpClient.cxx b/panda/src/downloader/httpClient.cxx index 83ab8ffb1d..1f1ee00631 100644 --- a/panda/src/downloader/httpClient.cxx +++ b/panda/src/downloader/httpClient.cxx @@ -193,6 +193,29 @@ HTTPClient:: unload_client_certificate(); } +//////////////////////////////////////////////////////////////////// +// Function: HTTPClient::init_random_seed +// Access: Published, Static +// Description: This may be called once, presumably at the beginning +// of an application, to initialize OpenSSL's random +// seed. On Windows, it is particularly important to +// call this at startup if you are going to be perfoming +// any https operations or otherwise use encryption, +// since the Windows algorithm for getting a random seed +// takes 2-3 seconds at startup, but can take 30 seconds +// or more after you have opened a 3-D graphics window +// and started rendering. +// +// There is no harm in calling this method multiple +// times, or in not calling it at all. +//////////////////////////////////////////////////////////////////// +void HTTPClient:: +init_random_seed() { + // This call is sufficient to kick OpenSSL into generating its + // random seed if it hasn't already. + RAND_status(); +} + //////////////////////////////////////////////////////////////////// // Function: HTTPClient::set_proxy_spec // Access: Published @@ -1354,13 +1377,6 @@ unload_client_certificate() { void HTTPClient:: initialize_ssl() { OpenSSL_add_all_algorithms(); - - // Call RAND_status() here to force the random number generator to - // initialize early. - if (early_random_seed) { - RAND_status(); - } - _ssl_initialized = true; } diff --git a/panda/src/downloader/httpClient.h b/panda/src/downloader/httpClient.h index ff15955470..5dca906d9d 100644 --- a/panda/src/downloader/httpClient.h +++ b/panda/src/downloader/httpClient.h @@ -65,6 +65,8 @@ PUBLISHED: void operator = (const HTTPClient ©); ~HTTPClient(); + static void init_random_seed(); + void set_proxy_spec(const string &proxy_spec); string get_proxy_spec() const;