@@ -68,15 +68,6 @@ struct grpc_end2end_http_proxy {
6868// Connection handling
6969//
7070
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-
8071// proxy_connection structure is only accessed in the closures which are all
8172// scheduled under the same combiner lock. So there is is no need for a mutex to
8273// protect this structure.
@@ -88,13 +79,6 @@ typedef struct proxy_connection {
8879
8980 gpr_refcount refcount;
9081
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-
9882 grpc_pollset_set* pollset_set;
9983
10084 // NOTE: All the closures execute under proxy->combiner lock. Which means
@@ -107,6 +91,13 @@ typedef struct proxy_connection {
10791 grpc_closure on_server_read_done;
10892 grpc_closure on_server_write_done;
10993
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+
110101 grpc_slice_buffer client_read_buffer;
111102 grpc_slice_buffer client_deferred_write_buffer;
112103 bool client_is_writing;
@@ -150,36 +141,52 @@ static void proxy_connection_unref(grpc_exec_ctx* exec_ctx,
150141 }
151142}
152143
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+
153152// Helper function to shut down the proxy connection.
154- // Does NOT take ownership of a reference to error.
155153static 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 ;
175169 }
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 ;
180174 }
181175 }
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.
182188 proxy_connection_unref (exec_ctx, conn, " conn_failed" );
189+ GRPC_ERROR_UNREF (error);
183190}
184191
185192// 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,
188195 proxy_connection* conn = (proxy_connection*)arg;
189196 conn->client_is_writing = false ;
190197 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) );
193200 return ;
194201 }
195202 // 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,
215222 proxy_connection* conn = (proxy_connection*)arg;
216223 conn->server_is_writing = false ;
217224 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) );
220227 return ;
221228 }
222229 // 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,
244251 if (error != GRPC_ERROR_NONE) {
245252 // Report a read failure on the client endpoint. If there is no pending
246253 // 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));
252256 return ;
253257 }
254258 // 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,
282286 if (error != GRPC_ERROR_NONE) {
283287 // Report a read failure on the server end point. If there is no pending
284288 // 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));
290291 return ;
291292 }
292293 // 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,
318319 proxy_connection* conn = (proxy_connection*)arg;
319320 conn->client_is_writing = false ;
320321 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) );
323324 return ;
324325 }
325326 // Clear write buffer.
@@ -347,8 +348,8 @@ static void on_server_connect_done(grpc_exec_ctx* exec_ctx, void* arg,
347348 // connection failed. However, for the purposes of this test code,
348349 // it's fine to pretend this is a client-side error, which will
349350 // 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) );
352353 return ;
353354 }
354355 // 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,
397398 gpr_log (GPR_DEBUG, " on_read_request_done: %p %s" , conn,
398399 grpc_error_string (error));
399400 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) );
402403 return ;
403404 }
404405 // 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,
407408 error = grpc_http_parser_parse (
408409 &conn->http_parser , conn->client_read_buffer .slices [i], nullptr );
409410 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));
412414 GRPC_ERROR_UNREF (error);
413415 return ;
414416 }
@@ -428,8 +430,8 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
428430 conn->http_request .method );
429431 error = GRPC_ERROR_CREATE_FROM_COPIED_STRING (msg);
430432 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) );
433435 GRPC_ERROR_UNREF (error);
434436 return ;
435437 }
@@ -449,8 +451,8 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
449451 if (!client_authenticated) {
450452 const char * msg = " HTTP Connect could not verify authentication" ;
451453 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) );
454456 GRPC_ERROR_UNREF (error);
455457 return ;
456458 }
@@ -460,8 +462,8 @@ static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
460462 error = grpc_blocking_resolve_address (conn->http_request .path , " 80" ,
461463 &resolved_addresses);
462464 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) );
465467 GRPC_ERROR_UNREF (error);
466468 return ;
467469 }
0 commit comments