@@ -68,15 +68,6 @@ struct grpc_end2end_http_proxy {
68
68
// Connection handling
69
69
//
70
70
71
- #define SERVER_EP_READ_FAIL 1
72
- #define SERVER_EP_WRITE_FAIL 2
73
- #define CLIENT_EP_READ_FAIL 4
74
- #define CLIENT_EP_WRITE_FAIL 8
75
-
76
- #define SERVER_EP_FAIL (SERVER_EP_READ_FAIL | SERVER_EP_WRITE_FAIL)
77
- #define CLIENT_EP_FAIL (CLIENT_EP_READ_FAIL | CLIENT_EP_WRITE_FAIL)
78
- #define EP_FAIL (SERVER_EP_FAIL | CLIENT_EP_FAIL)
79
-
80
71
// proxy_connection structure is only accessed in the closures which are all
81
72
// scheduled under the same combiner lock. So there is is no need for a mutex to
82
73
// protect this structure.
@@ -88,13 +79,6 @@ typedef struct proxy_connection {
88
79
89
80
gpr_refcount refcount;
90
81
91
- // The lower four bits store the endpoint failure information
92
- // bit-0 Server endpoint read failure
93
- // bit-1 Server endpoint write failure
94
- // bit-2 Client endpoint read failure
95
- // bit-3 Client endpoint write failure
96
- int ep_state;
97
-
98
82
grpc_pollset_set* pollset_set;
99
83
100
84
// NOTE: All the closures execute under proxy->combiner lock. Which means
@@ -107,6 +91,13 @@ typedef struct proxy_connection {
107
91
grpc_closure on_server_read_done;
108
92
grpc_closure on_server_write_done;
109
93
94
+ bool client_read_failed : 1 ;
95
+ bool client_write_failed : 1 ;
96
+ bool client_shutdown : 1 ;
97
+ bool server_read_failed : 1 ;
98
+ bool server_write_failed : 1 ;
99
+ bool server_shutdown : 1 ;
100
+
110
101
grpc_slice_buffer client_read_buffer;
111
102
grpc_slice_buffer client_deferred_write_buffer;
112
103
bool client_is_writing;
@@ -150,36 +141,52 @@ static void proxy_connection_unref(grpc_exec_ctx* exec_ctx,
150
141
}
151
142
}
152
143
144
+ enum failure_type {
145
+ SETUP_FAILED, // To be used before we start proxying.
146
+ CLIENT_READ_FAILED,
147
+ CLIENT_WRITE_FAILED,
148
+ SERVER_READ_FAILED,
149
+ SERVER_WRITE_FAILED,
150
+ };
151
+
153
152
// Helper function to shut down the proxy connection.
154
- // Does NOT take ownership of a reference to error.
155
153
static void proxy_connection_failed (grpc_exec_ctx* exec_ctx,
156
- proxy_connection* conn, int failure_type,
157
- const char * prefix, grpc_error* error) {
158
- const char * msg = grpc_error_string (error);
159
- gpr_log (GPR_INFO, " %s: %s" , prefix, msg);
160
- int ep_state = conn->ep_state ;
161
- int new_ep_state = ep_state | failure_type;
162
- if (ep_state != new_ep_state) {
163
- conn->ep_state = new_ep_state;
164
- // Shutdown the endpoint (client and/or server) if both read and write
165
- // failures are observed after setting the failure_type.
166
- // To prevent calling endpoint shutdown multiple times, It is important to
167
- // ensure that ep_state i.e the old state, did not already have both
168
- // failures set.
169
- if (((ep_state & SERVER_EP_FAIL) != SERVER_EP_FAIL) &&
170
- ((new_ep_state & SERVER_EP_FAIL) == SERVER_EP_FAIL)) {
171
- if (conn->server_endpoint != nullptr ) {
172
- grpc_endpoint_shutdown (exec_ctx, conn->server_endpoint ,
173
- GRPC_ERROR_REF (error));
174
- }
154
+ proxy_connection* conn,
155
+ failure_type failure, const char * prefix,
156
+ grpc_error* error) {
157
+ gpr_log (GPR_INFO, " %s: %s" , prefix, grpc_error_string (error));
158
+ // Decide whether we should shut down the client and server.
159
+ bool shutdown_client = false ;
160
+ bool shutdown_server = false ;
161
+ if (failure == SETUP_FAILED) {
162
+ shutdown_client = true ;
163
+ shutdown_server = true ;
164
+ } else {
165
+ if ((failure == CLIENT_READ_FAILED && conn->client_write_failed ) ||
166
+ (failure == CLIENT_WRITE_FAILED && conn->client_read_failed ) ||
167
+ (failure == SERVER_READ_FAILED && !conn->client_is_writing )) {
168
+ shutdown_client = true ;
175
169
}
176
- if (((ep_state & CLIENT_EP_FAIL) != CLIENT_EP_FAIL) &&
177
- ((new_ep_state & CLIENT_EP_FAIL) == CLIENT_EP_FAIL)) {
178
- grpc_endpoint_shutdown (exec_ctx, conn->client_endpoint ,
179
- GRPC_ERROR_REF (error)) ;
170
+ if ((failure == SERVER_READ_FAILED && conn-> server_write_failed ) ||
171
+ (failure == SERVER_WRITE_FAILED && conn-> server_read_failed ) ||
172
+ (failure == CLIENT_READ_FAILED && ! conn->server_is_writing )) {
173
+ shutdown_server = true ;
180
174
}
181
175
}
176
+ // If we decided to shut down either one and have not yet done so, do so.
177
+ if (shutdown_client && !conn->client_shutdown ) {
178
+ grpc_endpoint_shutdown (exec_ctx, conn->client_endpoint ,
179
+ GRPC_ERROR_REF (error));
180
+ conn->client_shutdown = true ;
181
+ }
182
+ if (shutdown_server && !conn->server_shutdown ) {
183
+ grpc_endpoint_shutdown (exec_ctx, conn->server_endpoint ,
184
+ GRPC_ERROR_REF (error));
185
+ conn->server_shutdown = true ;
186
+ }
187
+ // Unref the connection.
182
188
proxy_connection_unref (exec_ctx, conn, " conn_failed" );
189
+ GRPC_ERROR_UNREF (error);
183
190
}
184
191
185
192
// Callback for writing proxy data to the client.
@@ -188,8 +195,8 @@ static void on_client_write_done(grpc_exec_ctx* exec_ctx, void* arg,
188
195
proxy_connection* conn = (proxy_connection*)arg;
189
196
conn->client_is_writing = false ;
190
197
if (error != GRPC_ERROR_NONE) {
191
- proxy_connection_failed (exec_ctx, conn, CLIENT_EP_WRITE_FAIL ,
192
- " HTTP proxy client write" , error);
198
+ proxy_connection_failed (exec_ctx, conn, CLIENT_WRITE_FAILED ,
199
+ " HTTP proxy client write" , GRPC_ERROR_REF ( error) );
193
200
return ;
194
201
}
195
202
// Clear write buffer (the data we just wrote).
@@ -215,8 +222,8 @@ static void on_server_write_done(grpc_exec_ctx* exec_ctx, void* arg,
215
222
proxy_connection* conn = (proxy_connection*)arg;
216
223
conn->server_is_writing = false ;
217
224
if (error != GRPC_ERROR_NONE) {
218
- proxy_connection_failed (exec_ctx, conn, SERVER_EP_WRITE_FAIL ,
219
- " HTTP proxy server write" , error);
225
+ proxy_connection_failed (exec_ctx, conn, SERVER_WRITE_FAILED ,
226
+ " HTTP proxy server write" , GRPC_ERROR_REF ( error) );
220
227
return ;
221
228
}
222
229
// Clear write buffer (the data we just wrote).
@@ -244,11 +251,8 @@ static void on_client_read_done(grpc_exec_ctx* exec_ctx, void* arg,
244
251
if (error != GRPC_ERROR_NONE) {
245
252
// Report a read failure on the client endpoint. If there is no pending
246
253
// server write, then shutdown the server endpoint as well.
247
- proxy_connection_failed (
248
- exec_ctx, conn,
249
- (conn->server_is_writing ? CLIENT_EP_READ_FAIL
250
- : (CLIENT_EP_READ_FAIL | SERVER_EP_FAIL)),
251
- " HTTP proxy client read" , error);
254
+ proxy_connection_failed (exec_ctx, conn, CLIENT_READ_FAILED,
255
+ " HTTP proxy client read" , GRPC_ERROR_REF (error));
252
256
return ;
253
257
}
254
258
// If there is already a pending write (i.e., server_write_buffer is
@@ -282,11 +286,8 @@ static void on_server_read_done(grpc_exec_ctx* exec_ctx, void* arg,
282
286
if (error != GRPC_ERROR_NONE) {
283
287
// Report a read failure on the server end point. If there is no pending
284
288
// write to the client, then shutdown the client endpoint as well.
285
- proxy_connection_failed (
286
- exec_ctx, conn,
287
- (conn->client_is_writing ? SERVER_EP_READ_FAIL
288
- : (SERVER_EP_READ_FAIL | CLIENT_EP_FAIL)),
289
- " HTTP proxy server read" , error);
289
+ proxy_connection_failed (exec_ctx, conn, SERVER_READ_FAILED,
290
+ " HTTP proxy server read" , GRPC_ERROR_REF (error));
290
291
return ;
291
292
}
292
293
// If there is already a pending write (i.e., client_write_buffer is
@@ -318,8 +319,8 @@ static void on_write_response_done(grpc_exec_ctx* exec_ctx, void* arg,
318
319
proxy_connection* conn = (proxy_connection*)arg;
319
320
conn->client_is_writing = false ;
320
321
if (error != GRPC_ERROR_NONE) {
321
- proxy_connection_failed (exec_ctx, conn, EP_FAIL ,
322
- " HTTP proxy write response" , error);
322
+ proxy_connection_failed (exec_ctx, conn, SETUP_FAILED ,
323
+ " HTTP proxy write response" , GRPC_ERROR_REF ( error) );
323
324
return ;
324
325
}
325
326
// Clear write buffer.
@@ -347,8 +348,8 @@ static void on_server_connect_done(grpc_exec_ctx* exec_ctx, void* arg,
347
348
// connection failed. However, for the purposes of this test code,
348
349
// it's fine to pretend this is a client-side error, which will
349
350
// cause the client connection to be dropped.
350
- proxy_connection_failed (exec_ctx, conn, EP_FAIL ,
351
- " HTTP proxy server connect" , error);
351
+ proxy_connection_failed (exec_ctx, conn, SETUP_FAILED ,
352
+ " HTTP proxy server connect" , GRPC_ERROR_REF ( error) );
352
353
return ;
353
354
}
354
355
// We've established a connection, so send back a 200 response code to
@@ -397,8 +398,8 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
397
398
gpr_log (GPR_DEBUG, " on_read_request_done: %p %s" , conn,
398
399
grpc_error_string (error));
399
400
if (error != GRPC_ERROR_NONE) {
400
- proxy_connection_failed (exec_ctx, conn, EP_FAIL, " HTTP proxy read request " ,
401
- error);
401
+ proxy_connection_failed (exec_ctx, conn, SETUP_FAILED ,
402
+ " HTTP proxy read request " , GRPC_ERROR_REF ( error) );
402
403
return ;
403
404
}
404
405
// Read request and feed it to the parser.
@@ -407,8 +408,9 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
407
408
error = grpc_http_parser_parse (
408
409
&conn->http_parser , conn->client_read_buffer .slices [i], nullptr );
409
410
if (error != GRPC_ERROR_NONE) {
410
- proxy_connection_failed (exec_ctx, conn, EP_FAIL,
411
- " HTTP proxy request parse" , error);
411
+ proxy_connection_failed (exec_ctx, conn, SETUP_FAILED,
412
+ " HTTP proxy request parse" ,
413
+ GRPC_ERROR_REF (error));
412
414
GRPC_ERROR_UNREF (error);
413
415
return ;
414
416
}
@@ -428,8 +430,8 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
428
430
conn->http_request .method );
429
431
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING (msg);
430
432
gpr_free (msg);
431
- proxy_connection_failed (exec_ctx, conn, EP_FAIL, " HTTP proxy read request " ,
432
- error);
433
+ proxy_connection_failed (exec_ctx, conn, SETUP_FAILED ,
434
+ " HTTP proxy read request " , GRPC_ERROR_REF ( error) );
433
435
GRPC_ERROR_UNREF (error);
434
436
return ;
435
437
}
@@ -449,8 +451,8 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
449
451
if (!client_authenticated) {
450
452
const char * msg = " HTTP Connect could not verify authentication" ;
451
453
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING (msg);
452
- proxy_connection_failed (exec_ctx, conn, EP_FAIL ,
453
- " HTTP proxy read request" , error);
454
+ proxy_connection_failed (exec_ctx, conn, SETUP_FAILED ,
455
+ " HTTP proxy read request" , GRPC_ERROR_REF ( error) );
454
456
GRPC_ERROR_UNREF (error);
455
457
return ;
456
458
}
@@ -460,8 +462,8 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
460
462
error = grpc_blocking_resolve_address (conn->http_request .path , " 80" ,
461
463
&resolved_addresses);
462
464
if (error != GRPC_ERROR_NONE) {
463
- proxy_connection_failed (exec_ctx, conn, EP_FAIL, " HTTP proxy DNS lookup " ,
464
- error);
465
+ proxy_connection_failed (exec_ctx, conn, SETUP_FAILED ,
466
+ " HTTP proxy DNS lookup " , GRPC_ERROR_REF ( error) );
465
467
GRPC_ERROR_UNREF (error);
466
468
return ;
467
469
}
0 commit comments