Skip to content

Commit 7ce312e

Browse files
committed
gRPC: add gRPC wrapper classes to CMake build (#2015)
* add a C++ equivalent of `FIRFirestoreVersionString`. This eliminates the only Objective-C dependency of `grpc_connection.mm` and allows making it a pure C++ file; * open-source `binary_to_array.py` script and use it in the build to embed `roots.pem` certificate file from gRPC into the Firestore binary. The embedded char array is then used to load certificate at runtime.
1 parent 6ce83cc commit 7ce312e

20 files changed

+580
-63
lines changed

CMakeLists.txt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ set(
5959
CACHE PATH "Where to store downloaded files"
6060
)
6161

62+
set(
63+
FIREBASE_EXTERNAL_SOURCE_DIR
64+
${FIREBASE_BINARY_DIR}/external/src
65+
CACHE PATH "Root directory of source code of the external dependencies"
66+
)
67+
6268
download_external_sources()
6369

6470

@@ -103,8 +109,6 @@ set(gRPC_BUILD_TESTS OFF CACHE BOOL "Disable gRPC tests")
103109
add_external_subdirectory(grpc)
104110

105111
# Fix up targets included by gRPC's build
106-
set(external_src_dir ${FIREBASE_BINARY_DIR}/external/src)
107-
108112
if(OPENSSL_FOUND)
109113
# gRPC's CMakeLists.txt does not account for finding OpenSSL in a directory
110114
# that's not in the default search path.
@@ -127,14 +131,14 @@ else()
127131
target_include_directories(
128132
crypto
129133
INTERFACE
130-
$<BUILD_INTERFACE:${external_src_dir}/grpc/third_party/boringssl/include>
134+
$<BUILD_INTERFACE:${FIREBASE_EXTERNAL_SOURCE_DIR}/grpc/third_party/boringssl/include>
131135
)
132136

133137
add_alias(OpenSSL::SSL ssl)
134138
target_include_directories(
135139
ssl
136140
INTERFACE
137-
$<BUILD_INTERFACE:${external_src_dir}/grpc/third_party/boringssl/include>
141+
$<BUILD_INTERFACE:${FIREBASE_EXTERNAL_SOURCE_DIR}/grpc/third_party/boringssl/include>
138142
)
139143
endif()
140144

@@ -156,7 +160,7 @@ endif()
156160
if(NOT ZLIB_FOUND)
157161
target_include_directories(
158162
zlibstatic
159-
INTERFACE $<BUILD_INTERFACE:${external_src_dir}/grpc/third_party/zlib>
163+
INTERFACE $<BUILD_INTERFACE:${FIREBASE_EXTERNAL_SOURCE_DIR}/grpc/third_party/zlib>
160164
)
161165
endif()
162166

@@ -186,7 +190,7 @@ target_compile_definitions(
186190

187191
target_include_directories(
188192
protobuf-nanopb
189-
INTERFACE $<BUILD_INTERFACE:${external_src_dir}/nanopb>
193+
INTERFACE $<BUILD_INTERFACE:${FIREBASE_EXTERNAL_SOURCE_DIR}/nanopb>
190194
)
191195

192196

FirebaseFirestore.podspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling,
4040

4141
# Exclude alternate implementations for other platforms
4242
'Firestore/core/src/firebase/firestore/remote/connectivity_monitor_noop.cc',
43+
'Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder_generated.cc',
4344
'Firestore/core/src/firebase/firestore/util/filesystem_win.cc',
4445
'Firestore/core/src/firebase/firestore/util/hard_assert_stdio.cc',
4546
'Firestore/core/src/firebase/firestore/util/log_stdio.cc',

Firestore/Source/API/FIRFirestoreVersion.mm

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,11 @@
1616

1717
#import "Firestore/Source/API/FIRFirestoreVersion.h"
1818

19-
#ifndef FIRFirestore_VERSION
20-
#error "FIRFirestore_VERSION is not defined: add -DFIRFirestore_VERSION=... to the build invocation"
21-
#endif
19+
#include "Firestore/core/include/firebase/firestore/firestore_version.h"
2220

23-
// The following two macros supply the incantation so that the C
24-
// preprocessor does not try to parse the version as a floating
25-
// point number. See
26-
// https://www.guyrutenberg.com/2008/12/20/expanding-macros-into-string-constants-in-c/
27-
#define STR(x) STR_EXPAND(x)
28-
#define STR_EXPAND(x) #x
21+
using firebase::firestore::kFirestoreVersionString;
2922

23+
// Because `kFirestoreVersionString` is subject to constant initialization, this
24+
// is not affected by static initialization order fiasco.
3025
extern "C" const unsigned char *const FIRFirestoreVersionString =
31-
(const unsigned char *const)STR(FIRFirestore_VERSION);
26+
(const unsigned char *const)kFirestoreVersionString;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright 2018 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_FIRESTORE_VERSION_H_
18+
#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_FIRESTORE_VERSION_H_
19+
20+
/** Version for Firestore. */
21+
22+
namespace firebase {
23+
namespace firestore {
24+
25+
/** Version string for the Firebase Firestore SDK. */
26+
extern const char* const kFirestoreVersionString;
27+
28+
} // namespace firestore
29+
} // namespace firebase
30+
31+
#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_FIRESTORE_VERSION_H_

Firestore/core/src/firebase/firestore/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ cc_library(
2323
firebase_firestore_util
2424
)
2525

26+
cc_library(
27+
firebase_firestore_version
28+
SOURCES
29+
firestore_version.cc
30+
)
31+
32+
target_compile_definitions(
33+
firebase_firestore_version
34+
PRIVATE
35+
FIRFirestore_VERSION=0.13.6
36+
)
37+
2638
# Include the folder with public headers.
2739
target_include_directories(
2840
firebase_firestore_types
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2018 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "Firestore/core/include/firebase/firestore/firestore_version.h"
18+
19+
#ifndef FIRFirestore_VERSION
20+
#error \
21+
"FIRFirestore_VERSION is not defined: add -DFIRFirestore_VERSION=... to the build invocation" // NOLINT(whitespace/line_length)
22+
#endif
23+
24+
namespace firebase {
25+
namespace firestore {
26+
27+
// The following two macros supply the incantation so that the C
28+
// preprocessor does not try to parse the version as a floating
29+
// point number. See
30+
// https://www.guyrutenberg.com/2008/12/20/expanding-macros-into-string-constants-in-c/
31+
#define STR(x) STR_EXPAND(x)
32+
#define STR_EXPAND(x) #x
33+
34+
const char* const kFirestoreVersionString = STR(FIRFirestore_VERSION);
35+
36+
} // namespace firestore
37+
} // namespace firebase

Firestore/core/src/firebase/firestore/remote/CMakeLists.txt

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,62 @@ cc_select(
4242
DEFAULT firebase_firestore_remote_connectivity_monitor_noop
4343
)
4444

45+
# `roots.pem` is a file containing root certificates that is distributed
46+
# alongside gRPC and is necessary to establish SSL connections. Embed this file
47+
# into the binary by converting it to a char array.
48+
add_custom_command(
49+
OUTPUT grpc_root_certificates_generated.h grpc_root_certificates_generated.cc
50+
COMMAND ${FIREBASE_SOURCE_DIR}/scripts/binary_to_array.py
51+
--output_header=grpc_root_certificates_generated.h
52+
--output_source=grpc_root_certificates_generated.cc
53+
--cpp_namespace=firebase::firestore::remote
54+
--array=grpc_root_certificates
55+
--array_size=grpc_root_certificates_size
56+
${FIREBASE_EXTERNAL_SOURCE_DIR}/grpc/etc/roots.pem
57+
DEPENDS
58+
${FIREBASE_EXTERNAL_SOURCE_DIR}/grpc/etc/roots.pem
59+
)
60+
4561
cc_library(
4662
firebase_firestore_remote
4763
SOURCES
48-
grpc_util.h
49-
grpc_util.cc
50-
exponential_backoff.h
5164
exponential_backoff.cc
65+
exponential_backoff.h
66+
grpc_call.h
67+
grpc_completion.cc
68+
grpc_completion.h
69+
grpc_connection.cc
70+
grpc_connection.h
71+
grpc_root_certificate_finder.h
72+
grpc_root_certificate_finder_generated.cc
73+
grpc_root_certificates_generated.cc
74+
grpc_root_certificates_generated.h
75+
grpc_stream.cc
76+
grpc_stream.h
77+
grpc_stream_observer.h
78+
grpc_streaming_reader.cc
79+
grpc_streaming_reader.h
80+
grpc_unary_call.cc
81+
grpc_unary_call.h
82+
grpc_util.cc
83+
grpc_util.cc
84+
grpc_util.h
5285
serializer.h
5386
serializer.cc
87+
88+
# TODO(varconst): add these files once they no longer depend on Objective-C
89+
# serializer.
90+
# datastore.h
91+
# datastore.mm
92+
# remote_objc_bridge.h
93+
# remote_objc_bridge.mm
94+
# stream.h
95+
# stream.mm
96+
# watch_stream.h
97+
# watch_stream.mm
98+
# write_stream.h
99+
# write_stream.mm
100+
54101
DEPENDS
55102
# TODO(b/111328563) Force nanopb first to work around ODR violations
56103
protobuf-nanopb
@@ -60,5 +107,7 @@ cc_library(
60107
firebase_firestore_protos_nanopb
61108
firebase_firestore_remote_connectivity_monitor
62109
firebase_firestore_util
63-
grpc
110+
firebase_firestore_version
111+
112+
grpc++
64113
)

Firestore/core/src/firebase/firestore/remote/grpc_connection.mm renamed to Firestore/core/src/firebase/firestore/remote/grpc_connection.cc

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,21 @@
1717
#include "Firestore/core/src/firebase/firestore/remote/grpc_connection.h"
1818

1919
#include <algorithm>
20-
#include <fstream>
21-
#include <sstream>
2220
#include <string>
2321
#include <utility>
2422

2523
#include "Firestore/core/include/firebase/firestore/firestore_errors.h"
24+
#include "Firestore/core/include/firebase/firestore/firestore_version.h"
2625
#include "Firestore/core/src/firebase/firestore/auth/token.h"
2726
#include "Firestore/core/src/firebase/firestore/model/database_id.h"
2827
#include "Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder.h"
28+
#include "Firestore/core/src/firebase/firestore/util/filesystem.h"
2929
#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
3030
#include "Firestore/core/src/firebase/firestore/util/log.h"
3131
#include "Firestore/core/src/firebase/firestore/util/string_format.h"
3232
#include "absl/memory/memory.h"
3333
#include "grpcpp/create_channel.h"
3434

35-
#import "Firestore/Source/API/FIRFirestoreVersion.h"
36-
3735
namespace firebase {
3836
namespace firestore {
3937
namespace remote {
@@ -43,6 +41,7 @@
4341
using model::DatabaseId;
4442
using util::Path;
4543
using util::Status;
44+
using util::StatusOr;
4645
using util::StringFormat;
4746

4847
namespace {
@@ -54,22 +53,10 @@
5453
return view.data() ? std::string{view.data(), view.size()} : std::string{};
5554
}
5655

57-
std::string LoadCertificate(const Path& path) {
58-
std::ifstream certificate_file{path.native_value()};
59-
HARD_ASSERT(certificate_file.good(),
60-
StringFormat("Unable to open root certificates at file path %s",
61-
path.ToUtf8String())
62-
.c_str());
63-
64-
std::stringstream buffer;
65-
buffer << certificate_file.rdbuf();
66-
return buffer.str();
67-
}
68-
6956
std::shared_ptr<grpc::ChannelCredentials> CreateSslCredentials(
70-
const Path& certificate_path) {
57+
const std::string& certificate) {
7158
grpc::SslCredentialsOptions options;
72-
options.pem_root_certs = LoadCertificate(certificate_path);
59+
options.pem_root_certs = certificate;
7360
return grpc::SslCredentials(options);
7461
}
7562

@@ -132,8 +119,7 @@ bool HasSpecialConfig(const std::string& host) {
132119
// C++ SDK, etc.).
133120
context->AddMetadata(
134121
kXGoogAPIClientHeader,
135-
StringFormat("gl-objc/ fire/%s grpc/",
136-
reinterpret_cast<const char*>(FIRFirestoreVersionString)));
122+
StringFormat("gl-objc/ fire/%s grpc/", kFirestoreVersionString));
137123

138124
// This header is used to improve routing and project isolation by the
139125
// backend.
@@ -159,9 +145,8 @@ bool HasSpecialConfig(const std::string& host) {
159145
const std::string& host = database_info_->host();
160146

161147
if (!HasSpecialConfig(host)) {
162-
Path root_certificate_path = FindGrpcRootCertificate();
163-
return grpc::CreateChannel(host,
164-
CreateSslCredentials(root_certificate_path));
148+
std::string root_certificate = LoadGrpcRootCertificate();
149+
return grpc::CreateChannel(host, CreateSslCredentials(root_certificate));
165150
}
166151

167152
const HostConfig& host_config = Config()[host];
@@ -174,8 +159,15 @@ bool HasSpecialConfig(const std::string& host) {
174159
// For tests only
175160
grpc::ChannelArguments args;
176161
args.SetSslTargetNameOverride(host_config.target_name);
162+
Path path = host_config.certificate_path;
163+
StatusOr<std::string> test_certificate = ReadFile(path);
164+
HARD_ASSERT(test_certificate.ok(),
165+
StringFormat("Unable to open root certificates at file path %s",
166+
path.ToUtf8String())
167+
.c_str());
168+
177169
return grpc::CreateCustomChannel(
178-
host, CreateSslCredentials(host_config.certificate_path), args);
170+
host, CreateSslCredentials(test_certificate.ValueOrDie()), args);
179171
}
180172

181173
std::unique_ptr<GrpcStream> GrpcConnection::CreateStream(

Firestore/core/src/firebase/firestore/remote/grpc_root_certificate_finder.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ namespace firestore {
2626
namespace remote {
2727

2828
/**
29-
* Finds the file containing gRPC root certificates (`roots.pem`, must be among
30-
* resources accessible by Firestore) and returns its path. Will trigger
31-
* assertion failure if the file cannot be found.
29+
* Finds the file containing gRPC root certificates (how it is stored differs by
30+
* platform) and returns its contents as a string. Will trigger assertion
31+
* failure if the file cannot be found or open.
3232
*/
33-
util::Path FindGrpcRootCertificate();
33+
std::string LoadGrpcRootCertificate();
3434

3535
} // namespace remote
3636
} // namespace firestore

0 commit comments

Comments
 (0)