summaryrefslogtreecommitdiff
path: root/grpc/src/core/lib/iomgr/iomgr_posix_cfstream.cc
blob: 74cd19cc25a1440227409e334e9a60bfadbdeae5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

/// CFStream is build-enabled on iOS by default and disabled by default on other
/// platforms (see port_platform.h). To enable CFStream build on another
/// platform, the users need to define macro "GRPC_CFSTREAM=1" when building
/// gRPC.
///
/// When CFStream is to be built (either by default on iOS or by macro on other
/// platforms), the users can disable CFStream with environment variable
/// "grpc_cfstream=0". This will let gRPC to fallback to use POSIX sockets. In
/// addition, the users may choose to use an alternative CFRunLoop based pollset
/// "ev_apple" by setting environment variable "GRPC_CFSTREAM_RUN_LOOP=1". This
/// pollset resolves a bug from Apple when CFStream streams dispatch events to
/// dispatch queues. The caveat of this pollset is that users may not be able to
/// run a gRPC server in the same process.

#include <grpc/support/port_platform.h>

#include "src/core/lib/iomgr/port.h"

#ifdef GRPC_CFSTREAM_IOMGR

#include "src/core/lib/debug/trace.h"
#include "src/core/lib/iomgr/ev_apple.h"
#include "src/core/lib/iomgr/ev_posix.h"
#include "src/core/lib/iomgr/iomgr_internal.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/resolve_address_posix.h"
#include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/iomgr/tcp_posix.h"
#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/iomgr/timer.h"

static const char* grpc_cfstream_env_var = "grpc_cfstream";
static const char* grpc_cfstream_run_loop_env_var = "GRPC_CFSTREAM_RUN_LOOP";

extern grpc_tcp_server_vtable grpc_posix_tcp_server_vtable;
extern grpc_tcp_client_vtable grpc_posix_tcp_client_vtable;
extern grpc_tcp_client_vtable grpc_cfstream_client_vtable;
extern grpc_timer_vtable grpc_generic_timer_vtable;
extern grpc_pollset_vtable grpc_posix_pollset_vtable;
extern grpc_pollset_set_vtable grpc_posix_pollset_set_vtable;

static void apple_iomgr_platform_init(void) { grpc_pollset_global_init(); }

static void apple_iomgr_platform_flush(void) {}

static void apple_iomgr_platform_shutdown(void) {
  grpc_pollset_global_shutdown();
}

static void apple_iomgr_platform_shutdown_background_closure(void) {}

static bool apple_iomgr_platform_is_any_background_poller_thread(void) {
  return false;
}

static bool apple_iomgr_platform_add_closure_to_background_poller(
    grpc_closure* closure, grpc_error_handle error) {
  return false;
}

static grpc_iomgr_platform_vtable apple_vtable = {
    apple_iomgr_platform_init,
    apple_iomgr_platform_flush,
    apple_iomgr_platform_shutdown,
    apple_iomgr_platform_shutdown_background_closure,
    apple_iomgr_platform_is_any_background_poller_thread,
    apple_iomgr_platform_add_closure_to_background_poller};

namespace {
struct CFStreamEnv {
  bool enable_cfstream;
  bool enable_cfstream_run_loop;
};

// Parses environment variables for CFStream specific settings
CFStreamEnv ParseEnvForCFStream() {
  CFStreamEnv env;
  char* enable_cfstream_str = getenv(grpc_cfstream_env_var);
  env.enable_cfstream =
      enable_cfstream_str == nullptr || enable_cfstream_str[0] != '0';
  char* enable_cfstream_run_loop_str = getenv(grpc_cfstream_run_loop_env_var);
  // CFStream run-loop is disabled by default. The user has to enable it
  // explicitly with environment variable.
  env.enable_cfstream_run_loop = enable_cfstream_run_loop_str != nullptr &&
                                 enable_cfstream_run_loop_str[0] == '1';
  return env;
}

void MaybeInitializeTcpPosix(void) {
  CFStreamEnv env = ParseEnvForCFStream();
  if (!env.enable_cfstream || !env.enable_cfstream_run_loop) {
    grpc_tcp_posix_init();
  }
}

void MaybeShutdownTcpPosix(void) {
  CFStreamEnv env = ParseEnvForCFStream();
  if (!env.enable_cfstream || !env.enable_cfstream_run_loop) {
    grpc_tcp_posix_shutdown();
  }
}
}  // namespace

static void iomgr_platform_init(void) {
  MaybeInitializeTcpPosix();
  grpc_wakeup_fd_global_init();
  grpc_event_engine_init();
}

static void iomgr_platform_flush(void) {}

static void iomgr_platform_shutdown(void) {
  grpc_event_engine_shutdown();
  grpc_wakeup_fd_global_destroy();
  MaybeShutdownTcpPosix();
}

static void iomgr_platform_shutdown_background_closure(void) {
  grpc_shutdown_background_closure();
}

static bool iomgr_platform_is_any_background_poller_thread(void) {
  return grpc_is_any_background_poller_thread();
}

static bool iomgr_platform_add_closure_to_background_poller(
    grpc_closure* closure, grpc_error_handle error) {
  return grpc_add_closure_to_background_poller(closure, error);
}

static grpc_iomgr_platform_vtable vtable = {
    iomgr_platform_init,
    iomgr_platform_flush,
    iomgr_platform_shutdown,
    iomgr_platform_shutdown_background_closure,
    iomgr_platform_is_any_background_poller_thread,
    iomgr_platform_add_closure_to_background_poller};

void grpc_set_default_iomgr_platform() {
  CFStreamEnv env = ParseEnvForCFStream();
  if (!env.enable_cfstream) {
    // Use POSIX sockets for both client and server
    grpc_set_tcp_client_impl(&grpc_posix_tcp_client_vtable);
    grpc_set_tcp_server_impl(&grpc_posix_tcp_server_vtable);
    grpc_set_pollset_vtable(&grpc_posix_pollset_vtable);
    grpc_set_pollset_set_vtable(&grpc_posix_pollset_set_vtable);
    grpc_set_iomgr_platform_vtable(&vtable);
  } else if (env.enable_cfstream && !env.enable_cfstream_run_loop) {
    // Use CFStream with dispatch queue for client; use POSIX sockets for server
    grpc_set_tcp_client_impl(&grpc_cfstream_client_vtable);
    grpc_set_tcp_server_impl(&grpc_posix_tcp_server_vtable);
    grpc_set_pollset_vtable(&grpc_posix_pollset_vtable);
    grpc_set_pollset_set_vtable(&grpc_posix_pollset_set_vtable);
    grpc_set_iomgr_platform_vtable(&vtable);
  } else {
    // Use CFStream with CFRunLoop for client; server not supported
    grpc_set_tcp_client_impl(&grpc_cfstream_client_vtable);
    grpc_set_pollset_vtable(&grpc_apple_pollset_vtable);
    grpc_set_pollset_set_vtable(&grpc_apple_pollset_set_vtable);
    grpc_set_iomgr_platform_vtable(&apple_vtable);
  }
  grpc_set_timer_impl(&grpc_generic_timer_vtable);
  grpc_core::SetDNSResolver(grpc_core::NativeDNSResolver::GetOrCreate());
}

bool grpc_iomgr_run_in_background() {
  char* enable_cfstream_str = getenv(grpc_cfstream_env_var);
  bool enable_cfstream =
      enable_cfstream_str == nullptr || enable_cfstream_str[0] != '0';
  char* enable_cfstream_run_loop_str = getenv(grpc_cfstream_run_loop_env_var);
  // CFStream run-loop is disabled by default. The user has to enable it
  // explicitly with environment variable.
  bool enable_cfstream_run_loop = enable_cfstream_run_loop_str != nullptr &&
                                  enable_cfstream_run_loop_str[0] == '1';
  if (enable_cfstream && enable_cfstream_run_loop) {
    return false;
  } else {
    return grpc_event_engine_run_in_background();
  }
}

#endif /* GRPC_CFSTREAM_IOMGR */