diff options
author | Ben Murdoch <benm@google.com> | 2010-11-25 19:40:10 +0000 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-12-03 13:52:53 +0000 |
commit | 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7 (patch) | |
tree | 938665d93a11fe7a6d0124e3c1e020d1f9d3f947 /net/test | |
parent | 7c627d87728a355737862918d144f98f69406954 (diff) | |
download | chromium-4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7.tar.gz |
Merge Chromium at r66597: Initial merge by git.
Change-Id: I9639f8a997f90ec219573aa22a49f5dbde78cc7b
Diffstat (limited to 'net/test')
-rw-r--r-- | net/test/openssl_helper.cc | 264 | ||||
-rw-r--r-- | net/test/python_utils.cc | 30 | ||||
-rw-r--r-- | net/test/python_utils.h | 4 | ||||
-rw-r--r-- | net/test/test_server.cc | 151 | ||||
-rw-r--r-- | net/test/test_server.h | 19 | ||||
-rw-r--r-- | net/test/test_server_posix.cc | 47 | ||||
-rw-r--r-- | net/test/test_server_win.cc | 26 |
7 files changed, 432 insertions, 109 deletions
diff --git a/net/test/openssl_helper.cc b/net/test/openssl_helper.cc new file mode 100644 index 00000000..25989cb6 --- /dev/null +++ b/net/test/openssl_helper.cc @@ -0,0 +1,264 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This helper binary is only used for testing Chrome's SSL stack. + +#include <sys/types.h> +#include <sys/socket.h> + +#include <openssl/bio.h> +#include <openssl/ssl.h> +#include <openssl/err.h> + +static const char kDefaultPEMFile[] = "net/data/ssl/certificates/ok_cert.pem"; + +// Server Name Indication callback from OpenSSL +static int sni_cb(SSL *s, int *ad, void *arg) { + const char* servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); + if (servername && strcmp(servername, "test.example.com") == 0) + *reinterpret_cast<bool*>(arg) = true; + + return SSL_TLSEXT_ERR_OK; +} + +// Client certificate verification callback from OpenSSL +static int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { + return 1; +} + +// Next Protocol Negotiation callback from OpenSSL +static int next_proto_cb(SSL *ssl, const unsigned char **out, + unsigned int *outlen, void *arg) { + bool* npn_mispredict = reinterpret_cast<bool*>(arg); + static char kProtos[] = "\003foo\003bar"; + static char kProtos2[] = "\003baz\003boo"; + static unsigned count = 0; + + if (!*npn_mispredict || count == 0) { + *out = (const unsigned char*) kProtos; + *outlen = sizeof(kProtos) - 1; + } else { + *out = (const unsigned char*) kProtos2; + *outlen = sizeof(kProtos2) - 1; + } + count++; + return SSL_TLSEXT_ERR_OK; +} + +int +main(int argc, char **argv) { + SSL_library_init(); + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + SSL_load_error_strings(); + + bool sni = false, sni_good = false, snap_start = false; + bool snap_start_recovery = false, sslv3 = false, session_tickets = false; + bool fail_resume = false, client_cert = false, npn = false; + bool npn_mispredict = false; + + const char* key_file = kDefaultPEMFile; + const char* cert_file = kDefaultPEMFile; + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "sni") == 0) { + // Require SNI + sni = true; + } else if (strcmp(argv[i], "snap-start") == 0) { + // Support Snap Start + snap_start = true; + } else if (strcmp(argv[i], "snap-start-recovery") == 0) { + // Support Snap Start, but always trigger a recovery + snap_start = true; + snap_start_recovery = true; + } else if (strcmp(argv[i], "sslv3") == 0) { + // Use SSLv3 + sslv3 = true; + } else if (strcmp(argv[i], "session-tickets") == 0) { + // Enable Session Tickets + session_tickets = true; + } else if (strcmp(argv[i], "fail-resume") == 0) { + // Always fail to resume sessions + fail_resume = true; + } else if (strcmp(argv[i], "client-cert") == 0) { + // Request a client certificate + client_cert = true; + } else if (strcmp(argv[i], "npn") == 0) { + // Advertise NPN + npn = true; + } else if (strcmp(argv[i], "npn-mispredict") == 0) { + // Advertise NPN + npn = true; + npn_mispredict = true; + } else if (strcmp(argv[i], "--key-file") == 0) { + // Use alternative key file + i++; + if (i == argc) { + fprintf(stderr, "Missing argument to --key-file\n"); + return 1; + } + key_file = argv[i]; + } else if (strcmp(argv[i], "--cert-file") == 0) { + // Use alternative certificate file + i++; + if (i == argc) { + fprintf(stderr, "Missing argument to --cert-file\n"); + return 1; + } + cert_file = argv[i]; + } else { + fprintf(stderr, "Unknown argument: %s\n", argv[i]); + return 1; + } + } + + SSL_CTX* ctx; + + if (sslv3) { + ctx = SSL_CTX_new(SSLv3_server_method()); + } else { + ctx = SSL_CTX_new(TLSv1_server_method()); + } + + if (sni) { + SSL_CTX_set_tlsext_servername_callback(ctx, sni_cb); + SSL_CTX_set_tlsext_servername_arg(ctx, &sni_good); + } + + BIO* key = BIO_new(BIO_s_file()); + if (BIO_read_filename(key, key_file) <= 0) { + fprintf(stderr, "Failed to read %s\n", key_file); + return 1; + } + + EVP_PKEY *pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, NULL); + if (!pkey) { + fprintf(stderr, "Failed to parse %s\n", key_file); + return 1; + } + BIO_free(key); + + + BIO* cert = BIO_new(BIO_s_file()); + if (BIO_read_filename(cert, cert_file) <= 0) { + fprintf(stderr, "Failed to read %s\n", cert_file); + return 1; + } + + X509 *pcert = PEM_read_bio_X509_AUX(cert, NULL, NULL, NULL); + if (!pcert) { + fprintf(stderr, "Failed to parse %s\n", cert_file); + return 1; + } + BIO_free(cert); + + if (SSL_CTX_use_certificate(ctx, pcert) <= 0) { + fprintf(stderr, "Failed to load %s\n", cert_file); + return 1; + } + + if (SSL_CTX_use_PrivateKey(ctx, pkey) <= 0) { + fprintf(stderr, "Failed to load %s\n", key_file); + return 1; + } + + if (!SSL_CTX_check_private_key(ctx)) { + fprintf(stderr, "Public and private keys don't match\n"); + return 1; + } + + if (client_cert) + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb); + + if (session_tickets) + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH); + + if (snap_start) { + static const unsigned char orbit[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + SSL_CTX_set_snap_start_orbit(ctx, orbit); + } + + if (npn) + SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &npn_mispredict); + + unsigned connection_limit = 1; + if (snap_start || session_tickets) + connection_limit = 2; + if (npn_mispredict) + connection_limit = 3; + + for (unsigned connections = 0; connections < connection_limit; + connections++) { + const int fd = accept(3, NULL, NULL); + + SSL* server = SSL_new(ctx); + BIO* bio = BIO_new_socket(fd, 1 /* take ownership of fd */); + SSL_set_bio(server, bio, bio); + + if (fail_resume) { + SSL_set_session_id_context(server, (unsigned char*) &connections, + sizeof(connections)); + } + + int err; + for (;;) { + const int ret = SSL_accept(server); + if (ret == 1) + break; + + err = SSL_get_error(server, ret); + if (err == SSL_ERROR_WANT_READ) + continue; + if (err == SSL_ERROR_SERVER_RANDOM_VALIDATION_PENDING && snap_start) { + SSL_set_suggested_server_random_validity( + server, !snap_start_recovery); + continue; + } + ERR_print_errors_fp(stderr); + fprintf(stderr, "SSL_accept failed: %d\n", err); + return 1; + } + + if (sni && !sni_good) { + fprintf(stderr, "SNI failed\n"); + return 1; + } + + if (npn) { + const unsigned char *data, *expected_data; + unsigned len, expected_len; + SSL_get0_next_proto_negotiated(server, &data, &len); + if (!npn_mispredict || connections == 0) { + expected_data = (unsigned char*) "foo"; + expected_len = 3; + } else { + expected_data = (unsigned char*) "baz"; + expected_len = 3; + } + if (len != expected_len || memcmp(data, expected_data, len) != 0) { + fprintf(stderr, "Bad NPN: %d\n", len); + return 1; + } + } + + unsigned char buffer[6]; + + int ret = SSL_read(server, buffer, sizeof(buffer)); + if (ret == -1) { + err = SSL_get_error(server, ret); + ERR_print_errors_fp(stderr); + fprintf(stderr, "SSL_read failed: %d\n", err); + } + if (memcmp(buffer, "hello!", sizeof(buffer)) == 0) { + SSL_write(server, "goodbye!", 8); + } + + SSL_shutdown(server); + SSL_shutdown(server); + } + + SSL_CTX_free(ctx); + + return 0; +} diff --git a/net/test/python_utils.cc b/net/test/python_utils.cc index 438c3d72..13438f77 100644 --- a/net/test/python_utils.cc +++ b/net/test/python_utils.cc @@ -7,6 +7,7 @@ #include "base/base_paths.h" #include "base/environment.h" #include "base/file_path.h" +#include "base/file_util.h" #include "base/path_service.h" #include "base/scoped_ptr.h" #include "base/utf_string_conversions.h" @@ -36,6 +37,34 @@ void AppendToPythonPath(const FilePath& dir) { } } +bool GetPyProtoPath(FilePath* dir) { + // Locate the Python code generated by the protocol buffers compiler. + FilePath generated_code_dir; + if (!PathService::Get(base::DIR_EXE, &generated_code_dir)) { + return false; + } + + const FilePath kPyProto(FILE_PATH_LITERAL("pyproto")); + +#if defined(OS_MACOSX) || defined(OS_CHROMEOS) + // On Mac and Chrome OS, DIR_EXE might be pointing deep into the Release/ + // (or Debug/) directory and we can't depend on how far down it goes. So we + // walk upwards from DIR_EXE until we find a likely looking spot. + while (!file_util::DirectoryExists(generated_code_dir.Append(kPyProto))) { + FilePath parent = generated_code_dir.DirName(); + if (parent == generated_code_dir) { + // We hit the root directory. Maybe we didn't build any targets which + // produced Python protocol buffers. + PathService::Get(base::DIR_EXE, &generated_code_dir); + return false; + } + generated_code_dir = parent; + } +#endif + *dir = generated_code_dir.Append(kPyProto); + return true; +} + bool GetPythonRunTime(FilePath* dir) { #if defined(OS_WIN) if (!PathService::Get(base::DIR_SOURCE_ROOT, dir)) @@ -48,4 +77,3 @@ bool GetPythonRunTime(FilePath* dir) { #endif return true; } - diff --git a/net/test/python_utils.h b/net/test/python_utils.h index 215569ca..bc3bdb1a 100644 --- a/net/test/python_utils.h +++ b/net/test/python_utils.h @@ -16,8 +16,10 @@ extern const char kPythonPathEnv[]; // Appends the dir to python path environment variable. void AppendToPythonPath(const FilePath& dir); +// Return the location of the compiler-generated python protobuf. +bool GetPyProtoPath(FilePath* dir); + // Returns the path that should be used to launch Python. bool GetPythonRunTime(FilePath* path) WARN_UNUSED_RESULT; #endif // NET_TEST_PYTHON_UTILS_H_ - diff --git a/net/test/test_server.cc b/net/test/test_server.cc index 4b426eb4..0e8c4611 100644 --- a/net/test/test_server.cc +++ b/net/test/test_server.cc @@ -14,6 +14,7 @@ #include "net/base/x509_certificate.h" #endif +#include "base/base64.h" #include "base/command_line.h" #include "base/debug/leak_annotations.h" #include "base/file_util.h" @@ -40,59 +41,6 @@ const int kServerConnectionAttempts = 10; // Connection timeout in milliseconds for tests. const int kServerConnectionTimeoutMs = 1000; -const char kTestServerShardFlag[] = "test-server-shard"; - -int GetHTTPSPortBase(const TestServer::HTTPSOptions& options) { - if (options.request_client_certificate) - return 9543; - - switch (options.server_certificate) { - case TestServer::HTTPSOptions::CERT_OK: - return 9443; - case TestServer::HTTPSOptions::CERT_MISMATCHED_NAME: - return 9643; - case TestServer::HTTPSOptions::CERT_EXPIRED: - // TODO(phajdan.jr): Some tests rely on this hardcoded value. - // Some uses of this are actually in .html/.js files. - return 9666; - default: - NOTREACHED(); - } - return -1; -} - -int GetPortBase(TestServer::Type type, - const TestServer::HTTPSOptions& options) { - switch (type) { - case TestServer::TYPE_FTP: - return 3117; - case TestServer::TYPE_HTTP: - return 1337; - case TestServer::TYPE_HTTPS: - return GetHTTPSPortBase(options); - default: - NOTREACHED(); - } - return -1; -} - -int GetPort(TestServer::Type type, - const TestServer::HTTPSOptions& options) { - int port = GetPortBase(type, options); - if (CommandLine::ForCurrentProcess()->HasSwitch(kTestServerShardFlag)) { - std::string shard_str(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - kTestServerShardFlag)); - int shard = -1; - if (base::StringToInt(shard_str, &shard)) { - port += shard; - } else { - LOG(FATAL) << "Got invalid " << kTestServerShardFlag << " flag value. " - << "An integer is expected."; - } - } - return port; -} - std::string GetHostname(TestServer::Type type, const TestServer::HTTPSOptions& options) { if (type == TestServer::TYPE_HTTPS && @@ -138,13 +86,16 @@ FilePath TestServer::HTTPSOptions::GetCertificateFile() const { } TestServer::TestServer(Type type, const FilePath& document_root) - : type_(type) { + : type_(type), + started_(false) { Init(document_root); } TestServer::TestServer(const HTTPSOptions& https_options, const FilePath& document_root) - : https_options_(https_options), type_(TYPE_HTTPS) { + : https_options_(https_options), + type_(TYPE_HTTPS), + started_(false) { Init(document_root); } @@ -156,8 +107,11 @@ TestServer::~TestServer() { } void TestServer::Init(const FilePath& document_root) { - host_port_pair_ = HostPortPair(GetHostname(type_, https_options_), - GetPort(type_, https_options_)); + // At this point, the port that the testserver will listen on is unknown. + // The testserver will listen on an ephemeral port, and write the port + // number out over a pipe that this TestServer object will read from. Once + // that is complete, the host_port_pair_ will contain the actual port. + host_port_pair_ = HostPortPair(GetHostname(type_, https_options_), 0); process_handle_ = base::kNullProcessHandle; FilePath src_dir; @@ -202,6 +156,7 @@ bool TestServer::Start() { return false; } + started_ = true; return true; } @@ -209,6 +164,8 @@ bool TestServer::Stop() { if (!process_handle_) return true; + started_ = false; + // First check if the process has already terminated. bool ret = base::WaitForSingleProcess(process_handle_, 0); if (!ret) @@ -224,11 +181,17 @@ bool TestServer::Stop() { return ret; } +const HostPortPair& TestServer::host_port_pair() const { + DCHECK(started_); + return host_port_pair_; +} + std::string TestServer::GetScheme() const { switch (type_) { case TYPE_FTP: return "ftp"; case TYPE_HTTP: + case TYPE_SYNC: return "http"; case TYPE_HTTPS: return "https"; @@ -252,13 +215,13 @@ bool TestServer::GetAddressList(AddressList* address_list) const { return true; } -GURL TestServer::GetURL(const std::string& path) { +GURL TestServer::GetURL(const std::string& path) const { return GURL(GetScheme() + "://" + host_port_pair_.ToString() + "/" + path); } GURL TestServer::GetURLWithUser(const std::string& path, - const std::string& user) { + const std::string& user) const { return GURL(GetScheme() + "://" + user + "@" + host_port_pair_.ToString() + "/" + path); @@ -266,12 +229,47 @@ GURL TestServer::GetURLWithUser(const std::string& path, GURL TestServer::GetURLWithUserAndPassword(const std::string& path, const std::string& user, - const std::string& password) { + const std::string& password) const { return GURL(GetScheme() + "://" + user + ":" + password + "@" + host_port_pair_.ToString() + "/" + path); } +// static +bool TestServer::GetFilePathWithReplacements( + const std::string& original_file_path, + const std::vector<StringPair>& text_to_replace, + std::string* replacement_path) { + std::string new_file_path = original_file_path; + bool first_query_parameter = true; + const std::vector<StringPair>::const_iterator end = text_to_replace.end(); + for (std::vector<StringPair>::const_iterator it = text_to_replace.begin(); + it != end; + ++it) { + const std::string& old_text = it->first; + const std::string& new_text = it->second; + std::string base64_old; + std::string base64_new; + if (!base::Base64Encode(old_text, &base64_old)) + return false; + if (!base::Base64Encode(new_text, &base64_new)) + return false; + if (first_query_parameter) { + new_file_path += "?"; + first_query_parameter = false; + } else { + new_file_path += "&"; + } + new_file_path += "replace_text="; + new_file_path += base64_old; + new_file_path += ":"; + new_file_path += base64_new; + } + + *replacement_path = new_file_path; + return true; +} + bool TestServer::SetPythonPath() { FilePath third_party_dir; if (!PathService::Get(base::DIR_SOURCE_ROOT, &third_party_dir)) { @@ -284,33 +282,16 @@ bool TestServer::SetPythonPath() { AppendToPythonPath(third_party_dir.Append(FILE_PATH_LITERAL("pyftpdlib"))); // Locate the Python code generated by the protocol buffers compiler. - FilePath generated_code_dir; - if (!PathService::Get(base::DIR_EXE, &generated_code_dir)) { - LOG(ERROR) << "Failed to get DIR_EXE"; + FilePath pyproto_code_dir; + if (!GetPyProtoPath(&pyproto_code_dir)) { + LOG(ERROR) << "Failed to get python dir for generated code."; return false; } - static const FilePath kPyProto(FILE_PATH_LITERAL("pyproto")); - -#if defined(OS_MACOSX) - // On Mac, DIR_EXE might be pointing deep into the Release/ (or Debug/) - // directory and we can't depend on how far down it goes. So we walk upwards - // from DIR_EXE until we find a likely looking spot. - while (!file_util::DirectoryExists(generated_code_dir.Append(kPyProto))) { - FilePath parent = generated_code_dir.DirName(); - if (parent == generated_code_dir) { - // We hit the root directory. Maybe we didn't build any targets which - // produced Python protocol buffers. - PathService::Get(base::DIR_EXE, &generated_code_dir); - break; - } - generated_code_dir = parent; - } -#endif - - AppendToPythonPath(generated_code_dir.Append(kPyProto)); - AppendToPythonPath(generated_code_dir.Append(kPyProto). - Append(FILE_PATH_LITERAL("sync_pb"))); + AppendToPythonPath(pyproto_code_dir); + AppendToPythonPath(pyproto_code_dir.Append(FILE_PATH_LITERAL("sync_pb"))); + AppendToPythonPath(pyproto_code_dir.Append( + FILE_PATH_LITERAL("device_management_pb"))); return true; } @@ -350,6 +331,8 @@ bool TestServer::AddCommandLineArguments(CommandLine* command_line) const { if (type_ == TYPE_FTP) { command_line->AppendArg("-f"); + } else if (type_ == TYPE_SYNC) { + command_line->AppendArg("--sync"); } else if (type_ == TYPE_HTTPS) { FilePath certificate_path(certificates_dir_); certificate_path = certificate_path.Append( diff --git a/net/test/test_server.h b/net/test/test_server.h index 8affc12b..f8193654 100644 --- a/net/test/test_server.h +++ b/net/test/test_server.h @@ -7,6 +7,7 @@ #pragma once #include <string> +#include <utility> #include <vector> #include "build/build_config.h" @@ -41,6 +42,7 @@ class TestServer { TYPE_FTP, TYPE_HTTP, TYPE_HTTPS, + TYPE_SYNC, }; // Container for various options to control how the HTTPS server is @@ -113,18 +115,24 @@ class TestServer { bool Stop(); const FilePath& document_root() const { return document_root_; } - const HostPortPair& host_port_pair() const { return host_port_pair_; } + const HostPortPair& host_port_pair() const; std::string GetScheme() const; bool GetAddressList(AddressList* address_list) const WARN_UNUSED_RESULT; - GURL GetURL(const std::string& path); + GURL GetURL(const std::string& path) const; GURL GetURLWithUser(const std::string& path, - const std::string& user); + const std::string& user) const; GURL GetURLWithUserAndPassword(const std::string& path, const std::string& user, - const std::string& password); + const std::string& password) const; + + typedef std::pair<std::string, std::string> StringPair; + static bool GetFilePathWithReplacements( + const std::string& original_path, + const std::vector<StringPair>& text_to_replace, + std::string* replacement_path); private: void Init(const FilePath& document_root); @@ -189,6 +197,9 @@ class TestServer { Type type_; + // Has the server been started? + bool started_; + DISALLOW_COPY_AND_ASSIGN(TestServer); }; diff --git a/net/test/test_server_posix.cc b/net/test/test_server_posix.cc index 707eb931..9c0210b7 100644 --- a/net/test/test_server_posix.cc +++ b/net/test/test_server_posix.cc @@ -98,24 +98,45 @@ bool TestServer::LaunchPython(const FilePath& testserver_path) { } bool TestServer::WaitToStart() { - struct pollfd poll_fds[1]; - - poll_fds[0].fd = child_fd_; - poll_fds[0].events = POLLIN | POLLPRI; - poll_fds[0].revents = 0; + uint16 port; + uint8* buffer = reinterpret_cast<uint8*>(&port); + ssize_t bytes_read = 0; + ssize_t bytes_max = sizeof(port); + base::TimeDelta remaining_time = base::TimeDelta::FromMilliseconds( + TestTimeouts::action_max_timeout_ms()); + base::Time previous_time = base::Time::Now(); + while (bytes_read < bytes_max) { + struct pollfd poll_fds[1]; + + poll_fds[0].fd = child_fd_; + poll_fds[0].events = POLLIN | POLLPRI; + poll_fds[0].revents = 0; + + int rv = HANDLE_EINTR(poll(poll_fds, 1, remaining_time.InMilliseconds())); + if (rv != 1) { + LOG(ERROR) << "Failed to poll for the child file descriptor."; + return false; + } - int rv = HANDLE_EINTR(poll(poll_fds, 1, - TestTimeouts::action_max_timeout_ms())); - if (rv != 1) { - LOG(ERROR) << "Failed to poll for the child file descriptor."; - return false; + base::Time current_time = base::Time::Now(); + base::TimeDelta elapsed_time_cycle = current_time - previous_time; + DCHECK(elapsed_time_cycle.InMilliseconds() >= 0); + remaining_time -= elapsed_time_cycle; + previous_time = current_time; + + ssize_t num_bytes = HANDLE_EINTR(read(child_fd_, buffer + bytes_read, + bytes_max - bytes_read)); + if (num_bytes <= 0) + break; + bytes_read += num_bytes; } - char buf[8]; - ssize_t n = HANDLE_EINTR(read(child_fd_, buf, sizeof(buf))); // We don't need the FD anymore. child_fd_closer_.reset(NULL); - return n > 0; + if (bytes_read < bytes_max) + return false; + host_port_pair_.set_port(port); + return true; } bool TestServer::CheckCATrusted() { diff --git a/net/test/test_server_win.cc b/net/test/test_server_win.cc index c6e10d5b..64437cd4 100644 --- a/net/test/test_server_win.cc +++ b/net/test/test_server_win.cc @@ -156,11 +156,20 @@ bool TestServer::WaitToStart() { NewRunnableFunction(UnblockPipe, child_write_fd_.Get(), &unblocked), TestTimeouts::action_max_timeout_ms()); - char buf[8]; - DWORD bytes_read; - BOOL result = ReadFile(child_read_fd_.Get(), buf, sizeof(buf), &bytes_read, - NULL); - + // Try to read two bytes from the pipe indicating the ephemeral port number. + uint16 port; + uint8* buffer = reinterpret_cast<uint8*>(&port); + DWORD bytes_read = 0; + DWORD bytes_max = sizeof(port); + while (bytes_read < bytes_max) { + DWORD num_bytes; + if (!ReadFile(child_read_fd_, buffer + bytes_read, bytes_max - bytes_read, + &num_bytes, NULL)) + break; + if (num_bytes <= 0) + break; + bytes_read += num_bytes; + } thread.Stop(); child_read_fd_.Close(); child_write_fd_.Close(); @@ -169,7 +178,12 @@ bool TestServer::WaitToStart() { if (unblocked) return false; - return result && bytes_read > 0; + // If not enough bytes were read, fail. + if (bytes_read < bytes_max) + return false; + + host_port_pair_.set_port(port); + return true; } bool TestServer::CheckCATrusted() { |