|  | @@ -99,9 +99,9 @@ typedef struct connection_data {
 | 
	
		
			
				|  |  |    gpr_refcount refcount;
 | 
	
		
			
				|  |  |  } connection_data;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// Helper function to destroy the proxy connection.
 | 
	
		
			
				|  |  |  static void connection_data_destroy(grpc_exec_ctx* exec_ctx,
 | 
	
		
			
				|  |  |                                      connection_data* cd) {
 | 
	
		
			
				|  |  | -gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |    cd->proxy->shutdown = true;
 | 
	
		
			
				|  |  |    grpc_endpoint_destroy(exec_ctx, cd->client_endpoint);
 | 
	
		
			
				|  |  |    if (cd->server_endpoint != NULL)
 | 
	
	
		
			
				|  | @@ -116,54 +116,59 @@ gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |    gpr_free(cd);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// Helper function to shut down the proxy connection.
 | 
	
		
			
				|  |  | +// Does NOT take ownership of a reference to error.
 | 
	
		
			
				|  |  |  static void connection_data_failed(grpc_exec_ctx* exec_ctx,
 | 
	
		
			
				|  |  |                                     connection_data* cd, const char* prefix,
 | 
	
		
			
				|  |  |                                     grpc_error* error) {
 | 
	
		
			
				|  |  | -gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |    const char* msg = grpc_error_string(error);
 | 
	
		
			
				|  |  |    gpr_log(GPR_ERROR, "%s: %s", prefix, msg);
 | 
	
		
			
				|  |  |    grpc_error_free_string(msg);
 | 
	
		
			
				|  |  |    grpc_endpoint_shutdown(exec_ctx, cd->client_endpoint);
 | 
	
		
			
				|  |  |    if (cd->server_endpoint != NULL)
 | 
	
		
			
				|  |  |      grpc_endpoint_shutdown(exec_ctx, cd->server_endpoint);
 | 
	
		
			
				|  |  | -  if (gpr_unref(&cd->refcount)) {
 | 
	
		
			
				|  |  | +  if (gpr_unref(&cd->refcount))
 | 
	
		
			
				|  |  |      connection_data_destroy(exec_ctx, cd);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// Callback for writing proxy data to the client.
 | 
	
		
			
				|  |  |  static void on_client_write_done(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  |                                   grpc_error* error) {
 | 
	
		
			
				|  |  | -gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |    connection_data* cd = arg;
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      connection_data_failed(exec_ctx, cd, "HTTP proxy client write", error);
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  // Clear write buffer.
 | 
	
		
			
				|  |  | +  // Clear write buffer and release our reference.
 | 
	
		
			
				|  |  |    gpr_slice_buffer_reset_and_unref(&cd->client_write_buffer);
 | 
	
		
			
				|  |  | +  gpr_unref(&cd->refcount);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// Callback for writing proxy data to the backend server.
 | 
	
		
			
				|  |  |  static void on_server_write_done(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  |                                   grpc_error* error) {
 | 
	
		
			
				|  |  | -gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |    connection_data* cd = arg;
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      connection_data_failed(exec_ctx, cd, "HTTP proxy server write", error);
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  // Clear write buffer.
 | 
	
		
			
				|  |  | +  // Clear write buffer and release our reference.
 | 
	
		
			
				|  |  |    gpr_slice_buffer_reset_and_unref(&cd->server_write_buffer);
 | 
	
		
			
				|  |  | +  gpr_unref(&cd->refcount);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// Callback for reading data from the client, which will be proxied to
 | 
	
		
			
				|  |  | +// the backend server.
 | 
	
		
			
				|  |  |  static void on_client_read_done(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  |                                  grpc_error* error) {
 | 
	
		
			
				|  |  | -gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |    connection_data* cd = arg;
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      connection_data_failed(exec_ctx, cd, "HTTP proxy client read", error);
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    // Move read data into write buffer and write it.
 | 
	
		
			
				|  |  | +  // Take a new ref for the write callback.
 | 
	
		
			
				|  |  | +  gpr_ref(&cd->refcount);
 | 
	
		
			
				|  |  |    gpr_slice_buffer_move_into(&cd->client_read_buffer, &cd->server_write_buffer);
 | 
	
		
			
				|  |  |    grpc_endpoint_write(exec_ctx, cd->server_endpoint, &cd->server_write_buffer,
 | 
	
		
			
				|  |  |                        &cd->on_server_write_done);
 | 
	
	
		
			
				|  | @@ -172,15 +177,18 @@ gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |                       &cd->on_client_read_done);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// Callback for reading data from the backend server, which will be
 | 
	
		
			
				|  |  | +// proxied to the client.
 | 
	
		
			
				|  |  |  static void on_server_read_done(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  |                                  grpc_error* error) {
 | 
	
		
			
				|  |  | -gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |    connection_data* cd = arg;
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      connection_data_failed(exec_ctx, cd, "HTTP proxy server read", error);
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    // Move read data into write buffer and write it.
 | 
	
		
			
				|  |  | +  // Take a new ref for the write callback.
 | 
	
		
			
				|  |  | +  gpr_ref(&cd->refcount);
 | 
	
		
			
				|  |  |    gpr_slice_buffer_move_into(&cd->server_read_buffer, &cd->client_write_buffer);
 | 
	
		
			
				|  |  |    grpc_endpoint_write(exec_ctx, cd->client_endpoint, &cd->client_write_buffer,
 | 
	
		
			
				|  |  |                        &cd->on_client_write_done);
 | 
	
	
		
			
				|  | @@ -189,9 +197,9 @@ gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |                       &cd->on_server_read_done);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// Callback to write the HTTP response for the CONNECT request.
 | 
	
		
			
				|  |  |  static void on_write_response_done(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  |                                     grpc_error* error) {
 | 
	
		
			
				|  |  | -gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |    connection_data* cd = arg;
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      connection_data_failed(exec_ctx, cd, "HTTP proxy write response", error);
 | 
	
	
		
			
				|  | @@ -209,9 +217,10 @@ gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |                       &cd->on_server_read_done);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// Callback to connect to the backend server specified by the HTTP
 | 
	
		
			
				|  |  | +// CONNECT request.
 | 
	
		
			
				|  |  |  static void on_server_connect_done(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  |                                     grpc_error* error) {
 | 
	
		
			
				|  |  | -gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |    connection_data* cd = arg;
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      connection_data_failed(exec_ctx, cd, "HTTP proxy server connect", error);
 | 
	
	
		
			
				|  | @@ -225,9 +234,9 @@ gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |                        &cd->on_write_response_done);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// Callback to read the HTTP CONNECT request.
 | 
	
		
			
				|  |  |  static void on_read_request_done(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  |                                   grpc_error* error) {
 | 
	
		
			
				|  |  | -gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |    connection_data* cd = arg;
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      connection_data_failed(exec_ctx, cd, "HTTP proxy read request", error);
 | 
	
	
		
			
				|  | @@ -284,8 +293,6 @@ gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |  static void on_accept(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  |                        grpc_endpoint* ep, grpc_pollset* accepting_pollset,
 | 
	
		
			
				|  |  |                        grpc_tcp_server_acceptor* acceptor) {
 | 
	
		
			
				|  |  | -// FIXME: remove
 | 
	
		
			
				|  |  | -gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |    grpc_end2end_http_proxy* proxy = arg;
 | 
	
		
			
				|  |  |    // Instantiate connection_data.
 | 
	
		
			
				|  |  |    connection_data* cd = gpr_malloc(sizeof(*cd));
 | 
	
	
		
			
				|  | @@ -316,6 +323,24 @@ gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |  // Proxy class
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void thread_main(void* arg) {
 | 
	
		
			
				|  |  | +  grpc_end2end_http_proxy *proxy = arg;
 | 
	
		
			
				|  |  | +  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 | 
	
		
			
				|  |  | +  do {
 | 
	
		
			
				|  |  | +    const gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
 | 
	
		
			
				|  |  | +    const gpr_timespec deadline =
 | 
	
		
			
				|  |  | +        gpr_time_add(now, gpr_time_from_seconds(5, GPR_TIMESPAN));
 | 
	
		
			
				|  |  | +    grpc_pollset_worker *worker = NULL;
 | 
	
		
			
				|  |  | +    gpr_mu_lock(proxy->mu);
 | 
	
		
			
				|  |  | +    GRPC_LOG_IF_ERROR("grpc_pollset_work",
 | 
	
		
			
				|  |  | +                      grpc_pollset_work(&exec_ctx, proxy->pollset, &worker,
 | 
	
		
			
				|  |  | +                                        now, deadline));
 | 
	
		
			
				|  |  | +    gpr_mu_unlock(proxy->mu);
 | 
	
		
			
				|  |  | +    grpc_exec_ctx_flush(&exec_ctx);
 | 
	
		
			
				|  |  | +  } while (!proxy->shutdown);
 | 
	
		
			
				|  |  | +  grpc_exec_ctx_finish(&exec_ctx);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  grpc_end2end_http_proxy* grpc_end2end_http_proxy_create() {
 | 
	
		
			
				|  |  |    grpc_end2end_http_proxy* proxy = gpr_malloc(sizeof(*proxy));
 | 
	
		
			
				|  |  |    memset(proxy, 0, sizeof(*proxy));
 | 
	
	
		
			
				|  | @@ -323,8 +348,6 @@ grpc_end2end_http_proxy* grpc_end2end_http_proxy_create() {
 | 
	
		
			
				|  |  |    const int proxy_port = grpc_pick_unused_port_or_die();
 | 
	
		
			
				|  |  |    gpr_join_host_port(&proxy->proxy_name, "localhost", proxy_port);
 | 
	
		
			
				|  |  |    gpr_log(GPR_INFO, "Proxy address: %s", proxy->proxy_name);
 | 
	
		
			
				|  |  | -// FIXME: remove
 | 
	
		
			
				|  |  | -gpr_log(GPR_ERROR, "Proxy address: %s", proxy->proxy_name);
 | 
	
		
			
				|  |  |    // Create TCP server.
 | 
	
		
			
				|  |  |    proxy->channel_args = grpc_channel_args_copy(NULL);
 | 
	
		
			
				|  |  |    grpc_error* error = grpc_tcp_server_create(
 | 
	
	
		
			
				|  | @@ -347,32 +370,25 @@ gpr_log(GPR_ERROR, "Proxy address: %s", proxy->proxy_name);
 | 
	
		
			
				|  |  |    grpc_tcp_server_start(&exec_ctx, proxy->server, &proxy->pollset, 1,
 | 
	
		
			
				|  |  |                          on_accept, proxy);
 | 
	
		
			
				|  |  |    grpc_exec_ctx_finish(&exec_ctx);
 | 
	
		
			
				|  |  | -#if 0
 | 
	
		
			
				|  |  |    // Start proxy thread.
 | 
	
		
			
				|  |  |    gpr_thd_options opt = gpr_thd_options_default();
 | 
	
		
			
				|  |  |    gpr_thd_options_set_joinable(&opt);
 | 
	
		
			
				|  |  |    GPR_ASSERT(gpr_thd_new(&proxy->thd, thread_main, proxy, &opt));
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  |    return proxy;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p,
 | 
	
		
			
				|  |  | +static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |                              grpc_error *error) {
 | 
	
		
			
				|  |  | -  grpc_pollset_destroy(p);
 | 
	
		
			
				|  |  | -  gpr_free(p);
 | 
	
		
			
				|  |  | +  grpc_pollset* pollset = arg;
 | 
	
		
			
				|  |  | +  grpc_pollset_destroy(pollset);
 | 
	
		
			
				|  |  | +  gpr_free(pollset);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -// FIXME: remove (including all references below)
 | 
	
		
			
				|  |  | -//#define USE_THREAD 1
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  void grpc_end2end_http_proxy_destroy(grpc_end2end_http_proxy* proxy) {
 | 
	
		
			
				|  |  | -gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  |    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 | 
	
		
			
				|  |  | +  gpr_thd_join(proxy->thd);
 | 
	
		
			
				|  |  |    grpc_tcp_server_shutdown_listeners(&exec_ctx, proxy->server);
 | 
	
		
			
				|  |  |    grpc_tcp_server_unref(&exec_ctx, proxy->server);
 | 
	
		
			
				|  |  | -#ifdef USE_THREAD
 | 
	
		
			
				|  |  | -  gpr_thd_join(proxy->thd);
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  |    gpr_free(proxy->proxy_name);
 | 
	
		
			
				|  |  |    grpc_channel_args_destroy(proxy->channel_args);
 | 
	
		
			
				|  |  |    grpc_closure destroyed;
 | 
	
	
		
			
				|  | @@ -386,32 +402,3 @@ const char *grpc_end2end_http_proxy_get_proxy_name(
 | 
	
		
			
				|  |  |      grpc_end2end_http_proxy *proxy) {
 | 
	
		
			
				|  |  |    return proxy->proxy_name;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -static void thread_main(void* arg) {
 | 
	
		
			
				|  |  | -gpr_log(GPR_ERROR, "==> %s()", __func__);
 | 
	
		
			
				|  |  | -  grpc_end2end_http_proxy *proxy = arg;
 | 
	
		
			
				|  |  | -  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 | 
	
		
			
				|  |  | -  do {
 | 
	
		
			
				|  |  | -    const gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
 | 
	
		
			
				|  |  | -    const gpr_timespec deadline =
 | 
	
		
			
				|  |  | -        gpr_time_add(now, gpr_time_from_seconds(5, GPR_TIMESPAN));
 | 
	
		
			
				|  |  | -    grpc_pollset_worker *worker = NULL;
 | 
	
		
			
				|  |  | -    gpr_mu_lock(proxy->mu);
 | 
	
		
			
				|  |  | -    GRPC_LOG_IF_ERROR("grpc_pollset_work",
 | 
	
		
			
				|  |  | -                      grpc_pollset_work(&exec_ctx, proxy->pollset, &worker,
 | 
	
		
			
				|  |  | -                      now, deadline));
 | 
	
		
			
				|  |  | -    gpr_mu_unlock(proxy->mu);
 | 
	
		
			
				|  |  | -    grpc_exec_ctx_flush(&exec_ctx);
 | 
	
		
			
				|  |  | -  } while (!proxy->shutdown);
 | 
	
		
			
				|  |  | -  grpc_exec_ctx_finish(&exec_ctx);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void grpc_end2end_http_proxy_start_thread(grpc_end2end_http_proxy *proxy) {
 | 
	
		
			
				|  |  | -#ifdef USE_THREAD
 | 
	
		
			
				|  |  | -  gpr_thd_options opt = gpr_thd_options_default();
 | 
	
		
			
				|  |  | -  gpr_thd_options_set_joinable(&opt);
 | 
	
		
			
				|  |  | -  GPR_ASSERT(gpr_thd_new(&proxy->thd, thread_main, proxy, &opt));
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -  thread_main(proxy);
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -}
 |