| 
					
				 | 
			
			
				@@ -0,0 +1,836 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Copyright 2016, Google Inc. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * All rights reserved. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Redistribution and use in source and binary forms, with or without 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * modification, are permitted provided that the following conditions are 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * met: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     * Redistributions of source code must retain the above copyright 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * notice, this list of conditions and the following disclaimer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     * Redistributions in binary form must reproduce the above 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * copyright notice, this list of conditions and the following disclaimer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * in the documentation and/or other materials provided with the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * distribution. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *     * Neither the name of Google Inc. nor the names of its 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * contributors may be used to endorse or promote products derived from 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * this software without specific prior written permission. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/ext/lb_policy/grpclb/grpclb.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/ext/client_config/client_channel_factory.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/ext/client_config/lb_policy_registry.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/ext/client_config/parse_address.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/lib/iomgr/sockaddr_utils.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/lib/support/string.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/lib/surface/call.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/lib/surface/channel.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <string.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <grpc/byte_buffer_reader.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <grpc/grpc.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <grpc/support/alloc.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <grpc/support/host_port.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <grpc/support/string_util.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int grpc_lb_glb_trace = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+typedef struct wrapped_rr_closure_arg { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure *wrapped_closure; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_lb_policy *rr_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} wrapped_rr_closure_arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* The \a on_complete closure passed as part of the pick requires keeping a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * reference to its associated round robin instance. We wrap this closure in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * order to unref the round robin instance upon its invocation */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                               bool success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  wrapped_rr_closure_arg *wc = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (wc->rr_policy != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_INFO, "Unreffing RR %p", wc->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_UNREF(exec_ctx, wc->rr_policy, "wrapped_rr_closure"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (wc->wrapped_closure != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_exec_ctx_enqueue(exec_ctx, wc->wrapped_closure, success, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_free(wc); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+typedef struct pending_pick { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  struct pending_pick *next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_polling_entity *pollent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_metadata_batch *initial_metadata; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  uint32_t initial_metadata_flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connected_subchannel **target; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure *wrapped_on_complete; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  wrapped_rr_closure_arg *wrapped_on_complete_arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} pending_pick; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+typedef struct pending_ping { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  struct pending_ping *next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure *wrapped_notify; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  wrapped_rr_closure_arg *wrapped_notify_arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} pending_ping; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+typedef struct glb_lb_policy glb_lb_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define MAX_LBCD_OPS_LEN 6 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+typedef struct lb_client_data { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu mu; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure md_sent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure md_rcvd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure req_sent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure res_rcvd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure close_sent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure srv_status_rcvd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_call *c; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_timespec deadline; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_metadata_array initial_metadata_recv; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_metadata_array trailing_metadata_recv; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_byte_buffer *request_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_byte_buffer *response_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_status_code status; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char *status_details; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  size_t status_details_capacity; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} lb_client_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Keeps track and reacts to changes in connectivity of the RR instance */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+typedef struct rr_connectivity_data { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure on_change; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state state; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} rr_connectivity_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+struct glb_lb_policy { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** base policy: must be first */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_lb_policy base; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** mutex protecting remaining members */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu mu; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_client_channel_factory *cc_factory; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** for communicating with the LB server */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_channel *lb_server_channel; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** the RR policy to use of the backend servers returned by the LB server */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_lb_policy *rr_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  bool started_picking; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** our connectivity state tracker */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state_tracker state_tracker; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_grpclb_serverlist *serverlist; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** list of picks that are waiting on connectivity */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pending_pick *pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** list of pings that are waiting on connectivity */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pending_ping *pending_pings; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** data associated with the communication with the LB server */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lb_client_data *lbcd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** for tracking of the RR connectivity */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  rr_connectivity_data *rr_connectivity; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void rr_handover(grpc_exec_ctx *exec_ctx, glb_lb_policy *p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    bool iomgr_success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  rr_connectivity_data *rrcd = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!iomgr_success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_free(rrcd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p = rrcd->p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const grpc_connectivity_state new_state = p->rr_connectivity->state; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (new_state == GRPC_CHANNEL_SHUTDOWN && p->serverlist != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* a RR policy is shutting down but there's a serverlist available -> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * perform a handover */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    rr_handover(exec_ctx, p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_connectivity_state_set(exec_ctx, &p->state_tracker, new_state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                "rr_connectivity_changed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* resubscribe */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_lb_policy_notify_on_state_change(exec_ctx, p->rr_policy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                          &p->rr_connectivity->state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                          &p->rr_connectivity->on_change); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void add_pending_pick(pending_pick **root, grpc_polling_entity *pollent, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                             grpc_metadata_batch *initial_metadata, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                             uint32_t initial_metadata_flags, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                             grpc_connected_subchannel **target, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                             grpc_closure *on_complete) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pending_pick *pp = gpr_malloc(sizeof(*pp)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(pp, 0, sizeof(pending_pick)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pp->wrapped_on_complete_arg = gpr_malloc(sizeof(wrapped_rr_closure_arg)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(pp->wrapped_on_complete_arg, 0, sizeof(wrapped_rr_closure_arg)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pp->next = *root; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pp->pollent = pollent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pp->target = target; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pp->initial_metadata = initial_metadata; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pp->initial_metadata_flags = initial_metadata_flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pp->wrapped_on_complete = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_closure_create(wrapped_rr_closure, pp->wrapped_on_complete_arg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pp->wrapped_on_complete_arg->wrapped_closure = on_complete; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  *root = pp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void add_pending_ping(pending_ping **root, grpc_closure *notify) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pending_ping *pping = gpr_malloc(sizeof(*pping)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(pping, 0, sizeof(pending_ping)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pping->wrapped_notify_arg = gpr_malloc(sizeof(wrapped_rr_closure_arg)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(pping->wrapped_notify_arg, 0, sizeof(wrapped_rr_closure_arg)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pping->next = *root; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pping->wrapped_notify = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_closure_create(wrapped_rr_closure, pping->wrapped_notify_arg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pping->wrapped_notify_arg->wrapped_closure = notify; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  *root = pping; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void lb_client_data_destroy(lb_client_data *lbcd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void md_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, bool success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lb_client_data *lbcd = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(lbcd->c); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_call_error error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_op ops[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(ops, 0, sizeof(ops)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_op *op = ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->op = GRPC_OP_RECV_INITIAL_METADATA; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.recv_initial_metadata = &lbcd->initial_metadata_recv; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  error = grpc_call_start_batch_and_execute(exec_ctx, lbcd->c, ops, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                            (size_t)(op - ops), &lbcd->md_rcvd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(GRPC_CALL_OK == error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void md_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, bool success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lb_client_data *lbcd = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(lbcd->c); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_call_error error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_op ops[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(ops, 0, sizeof(ops)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_op *op = ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->op = GRPC_OP_SEND_MESSAGE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.send_message = lbcd->request_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      exec_ctx, lbcd->c, ops, (size_t)(op - ops), &lbcd->req_sent); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(GRPC_CALL_OK == error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void req_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, bool success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lb_client_data *lbcd = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_call_error error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_op ops[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(ops, 0, sizeof(ops)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_op *op = ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->op = GRPC_OP_RECV_MESSAGE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.recv_message = &lbcd->response_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      exec_ctx, lbcd->c, ops, (size_t)(op - ops), &lbcd->res_rcvd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(GRPC_CALL_OK == error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void res_rcvd_cb(grpc_exec_ctx *exec_ctx, void *arg, bool success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* look inside lbcd->response_payload, ideally to send it back as the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * serverlist. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lb_client_data *lbcd = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_op ops[2]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(ops, 0, sizeof(ops)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_op *op = ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (lbcd->response_payload) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_byte_buffer_reader bbr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_byte_buffer_reader_init(&bbr, lbcd->response_payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_slice response_slice = grpc_byte_buffer_reader_readall(&bbr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_byte_buffer_destroy(lbcd->response_payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_grpclb_serverlist *serverlist = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grpc_grpclb_response_parse_serverlist(response_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (serverlist) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_slice_unref(response_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gpr_log(GPR_INFO, "Serverlist with %zu servers received", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                serverlist->num_servers); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* update serverlist */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (serverlist->num_servers > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (grpc_grpclb_serverlist_equals(lbcd->p->serverlist, serverlist)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          gpr_log(GPR_INFO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  "Incoming server list identical to current, ignoring."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (lbcd->p->serverlist != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            grpc_grpclb_destroy_serverlist(lbcd->p->serverlist); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          lbcd->p->serverlist = serverlist; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (lbcd->p->rr_policy == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* initial "handover", in this case from a null RR policy, meaning it'll 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         * just create the first one */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        rr_handover(exec_ctx, lbcd->p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* unref the RR policy, eventually leading to its substitution with a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         * new one constructed from the received serverlist (see 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         * rr_connectivity_changed) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        GRPC_LB_POLICY_UNREF(exec_ctx, lbcd->p->rr_policy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                             "serverlist_received"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* listen for a potential serverlist update */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      op->op = GRPC_OP_RECV_MESSAGE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      op->data.recv_message = &lbcd->response_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const grpc_call_error error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          exec_ctx, lbcd->c, ops, (size_t)(op - ops), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          &lbcd->res_rcvd); /* loop */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      GPR_ASSERT(GRPC_CALL_OK == error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_ERROR, "Invalid LB response received: '%s'", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              gpr_dump_slice(response_slice, GPR_DUMP_ASCII)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_slice_unref(response_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* Disconnect from server returning invalid response. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_call_error error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          exec_ctx, lbcd->c, ops, (size_t)(op - ops), &lbcd->close_sent); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      GPR_ASSERT(GRPC_CALL_OK == error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* empty payload: call cancelled by server. Cleanups happening in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * srv_status_rcvd_cb */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void close_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, bool success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_log(GPR_INFO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "Close from LB client sent. Waiting from server status now"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void srv_status_rcvd_cb(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                               bool success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lb_client_data *lbcd = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p = lbcd->p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_log( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        GPR_INFO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        "status from lb server received. Status = %d, Details = '%s', Capaticy " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        "= %zu", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        lbcd->status, lbcd->status_details, lbcd->status_details_capacity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_call_destroy(lbcd->c); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_channel_destroy(lbcd->p->lb_server_channel); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lbcd->p->lb_server_channel = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lb_client_data_destroy(lbcd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->lbcd = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static lb_client_data *lb_client_data_create(glb_lb_policy *p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lb_client_data *lbcd = gpr_malloc(sizeof(lb_client_data)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(lbcd, 0, sizeof(lb_client_data)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_init(&lbcd->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure_init(&lbcd->md_sent, md_sent_cb, lbcd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure_init(&lbcd->md_rcvd, md_recv_cb, lbcd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure_init(&lbcd->req_sent, req_sent_cb, lbcd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure_init(&lbcd->res_rcvd, res_rcvd_cb, lbcd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure_init(&lbcd->close_sent, close_sent_cb, lbcd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure_init(&lbcd->srv_status_rcvd, srv_status_rcvd_cb, lbcd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* TODO(dgq): get the deadline from the client/user instead of fabricating 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * one 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * here. Make it a policy arg? */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lbcd->deadline = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                gpr_time_from_seconds(3, GPR_TIMESPAN)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lbcd->c = grpc_channel_create_pollset_set_call( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      p->lb_server_channel, NULL, GRPC_PROPAGATE_DEFAULTS, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      p->base.interested_parties, "/BalanceLoad", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      NULL, /* FIXME(dgq): which "host" value to use? */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      lbcd->deadline, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_metadata_array_init(&lbcd->initial_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_metadata_array_init(&lbcd->trailing_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_grpclb_request *request = grpc_grpclb_request_create( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      "load.balanced.service.name"); /* FIXME(dgq): get the name of the load 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                        balanced service from above. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_slice request_payload_slice = grpc_grpclb_request_encode(request); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lbcd->request_payload = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_raw_byte_buffer_create(&request_payload_slice, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_slice_unref(request_payload_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_grpclb_request_destroy(request); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lbcd->status_details = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lbcd->status_details_capacity = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lbcd->p = p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return lbcd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void lb_client_data_destroy(lb_client_data *lbcd) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_metadata_array_destroy(&lbcd->initial_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_metadata_array_destroy(&lbcd->trailing_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_byte_buffer_destroy(lbcd->request_payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_free(lbcd->status_details); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_destroy(&lbcd->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_free(lbcd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void glb_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p = (glb_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(p->pending_picks == NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(p->pending_pings == NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (p->serverlist != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_grpclb_destroy_serverlist(p->serverlist); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_destroy(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_free(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void glb_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p = (glb_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pending_pick *pp = p->pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->pending_picks = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pending_ping *pping = p->pending_pings; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->pending_pings = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  while (pp != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pending_pick *next = pp->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    *pp->target = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_exec_ctx_enqueue(exec_ctx, pp->wrapped_on_complete, true, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_free(pp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pp = next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  while (pping != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pending_ping *next = pping->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_exec_ctx_enqueue(exec_ctx, pping->wrapped_notify, true, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pping = next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (p->rr_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* unsubscribe */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_lb_policy_notify_on_state_change(exec_ctx, p->rr_policy, NULL, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                          &p->rr_connectivity->on_change); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_UNREF(exec_ctx, p->rr_policy, "glb_shutdown"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state_set(exec_ctx, &p->state_tracker, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              GRPC_CHANNEL_SHUTDOWN, "glb_shutdown"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void glb_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            grpc_connected_subchannel **target) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p = (glb_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pending_pick *pp = p->pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->pending_picks = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  while (pp != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pending_pick *next = pp->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (pp->target == target) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                               p->base.interested_parties); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      *target = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_exec_ctx_enqueue(exec_ctx, pp->wrapped_on_complete, false, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_free(pp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      pp->next = p->pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      p->pending_picks = pp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pp = next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void glb_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                             uint32_t initial_metadata_flags_mask, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                             uint32_t initial_metadata_flags_eq) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p = (glb_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (p->lbcd != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* cancel the call to the load balancer service, if any */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_call_cancel(p->lbcd->c, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pending_pick *pp = p->pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->pending_picks = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  while (pp != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pending_pick *next = pp->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if ((pp->initial_metadata_flags & initial_metadata_flags_mask) == 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        initial_metadata_flags_eq) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_polling_entity_del_from_pollset_set(exec_ctx, pp->pollent, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                               p->base.interested_parties); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_exec_ctx_enqueue(exec_ctx, pp->wrapped_on_complete, false, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_free(pp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      pp->next = p->pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      p->pending_picks = pp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pp = next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void query_for_backends(grpc_exec_ctx *exec_ctx, glb_lb_policy *p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(p->lb_server_channel != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->lbcd = lb_client_data_create(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_call_error error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_op ops[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(ops, 0, sizeof(ops)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_op *op = ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->op = GRPC_OP_SEND_INITIAL_METADATA; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.send_initial_metadata.count = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      exec_ctx, p->lbcd->c, ops, (size_t)(op - ops), &p->lbcd->md_sent); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(GRPC_CALL_OK == error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op = ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.recv_status_on_client.trailing_metadata = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      &p->lbcd->trailing_metadata_recv; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.recv_status_on_client.status = &p->lbcd->status; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.recv_status_on_client.status_details = &p->lbcd->status_details; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.recv_status_on_client.status_details_capacity = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      &p->lbcd->status_details_capacity; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      exec_ctx, p->lbcd->c, ops, (size_t)(op - ops), &p->lbcd->srv_status_rcvd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(GRPC_CALL_OK == error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static grpc_lb_policy *create_rr(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                 const grpc_grpclb_serverlist *serverlist, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                 glb_lb_policy *p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* TODO(dgq): support mixed ip version */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(serverlist != NULL && serverlist->num_servers > 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char **host_ports = gpr_malloc(sizeof(char *) * serverlist->num_servers); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (size_t i = 0; i < serverlist->num_servers; ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_join_host_port(&host_ports[i], serverlist->servers[i]->ip_address, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                       serverlist->servers[i]->port); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  size_t uri_path_len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char *concat_ipports = gpr_strjoin_sep( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (const char **)host_ports, serverlist->num_servers, ",", &uri_path_len); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_lb_policy_args args; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  args.client_channel_factory = p->cc_factory; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  args.addresses = gpr_malloc(sizeof(grpc_resolved_addresses)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  args.addresses->naddrs = serverlist->num_servers; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  args.addresses->addrs = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_malloc(sizeof(grpc_resolved_address) * args.addresses->naddrs); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  size_t out_addrs_idx = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (size_t i = 0; i < serverlist->num_servers; ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_uri uri; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    struct sockaddr_storage sa; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    size_t sa_len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    uri.path = host_ports[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (parse_ipv4(&uri, &sa, &sa_len)) { /* TODO(dgq): add support for ipv6 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      memcpy(args.addresses->addrs[out_addrs_idx].addr, &sa, sa_len); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      args.addresses->addrs[out_addrs_idx].len = sa_len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ++out_addrs_idx; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_ERROR, "Invalid LB service address '%s', ignoring.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              host_ports[i]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_lb_policy *rr = grpc_lb_policy_create(exec_ctx, "round_robin", &args); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_free(concat_ipports); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (size_t i = 0; i < serverlist->num_servers; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_free(host_ports[i]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_free(host_ports); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_free(args.addresses->addrs); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_free(args.addresses); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return rr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void start_picking(grpc_exec_ctx *exec_ctx, glb_lb_policy *p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->started_picking = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  query_for_backends(exec_ctx, p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void rr_handover(grpc_exec_ctx *exec_ctx, glb_lb_policy *p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->rr_policy = create_rr(exec_ctx, p->serverlist, p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_log(GPR_INFO, "Created RR policy (0x%" PRIxPTR ")", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (intptr_t)p->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(p->rr_policy != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->rr_connectivity->state = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_lb_policy_check_connectivity(exec_ctx, p->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_lb_policy_notify_on_state_change(exec_ctx, p->rr_policy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                        &p->rr_connectivity->state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                        &p->rr_connectivity->on_change); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state_set(exec_ctx, &p->state_tracker, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              p->rr_connectivity->state, "rr_handover"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_lb_policy_exit_idle(exec_ctx, p->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* flush pending ops */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pending_pick *pp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  while ((pp = p->pending_picks)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    p->pending_picks = pp->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_REF(p->rr_policy, "rr_handover_pending_pick"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pp->wrapped_on_complete_arg->rr_policy = p->rr_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_INFO, "Pending pick about to PICK from 0x%"PRIxPTR"", (intptr_t)p->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_lb_policy_pick(exec_ctx, p->rr_policy, pp->pollent, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        pp->initial_metadata, pp->initial_metadata_flags, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        pp->target, pp->wrapped_on_complete); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_free(pp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pending_ping *pping; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  while ((pping = p->pending_pings)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    p->pending_pings = pping->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_REF(p->rr_policy, "rr_handover_pending_ping"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pping->wrapped_notify_arg->rr_policy = p->rr_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_INFO, "Pending ping about to PING from 0x%"PRIxPTR"", (intptr_t)p->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_lb_policy_ping_one(exec_ctx, p->rr_policy, pping->wrapped_notify); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_free(pping); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void glb_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p = (glb_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!p->started_picking) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    start_picking(exec_ctx, p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int glb_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    grpc_polling_entity *pollent, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    grpc_metadata_batch *initial_metadata, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    uint32_t initial_metadata_flags, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    grpc_connected_subchannel **target, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    grpc_closure *on_complete) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p = (glb_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int r; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (p->rr_policy != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_INFO, "about to PICK from 0x%"PRIxPTR"", (intptr_t)p->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_REF(p->rr_policy, "rr_pick"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    wrapped_rr_closure_arg *warg = gpr_malloc(sizeof(wrapped_rr_closure_arg)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    warg->rr_policy = p->rr_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    warg->wrapped_closure = on_complete; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_closure *wrapped_on_complete = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grpc_closure_create(wrapped_rr_closure, warg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    r = grpc_lb_policy_pick(exec_ctx, p->rr_policy, pollent, initial_metadata, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            initial_metadata_flags, target, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            wrapped_on_complete); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (r != 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* the call to grpc_lb_policy_pick has been sychronous. Invoke a neutered 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * wrapped closure */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      warg->wrapped_closure = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_exec_ctx_enqueue(exec_ctx, wrapped_on_complete, false, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_polling_entity_add_to_pollset_set(exec_ctx, pollent, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                           p->base.interested_parties); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    add_pending_pick(&p->pending_picks, pollent, initial_metadata, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                     initial_metadata_flags, target, on_complete); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!p->started_picking) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      start_picking(exec_ctx, p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    r = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return r; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static grpc_connectivity_state glb_check_connectivity(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                      grpc_lb_policy *pol) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p = (glb_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state st; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  st = grpc_connectivity_state_check(&p->state_tracker); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return st; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void glb_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                         grpc_closure *closure) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p = (glb_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (p->rr_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_lb_policy_ping_one(exec_ctx, p->rr_policy, closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    add_pending_ping(&p->pending_pings, closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!p->started_picking) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      start_picking(exec_ctx, p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void glb_notify_on_state_change(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                       grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                       grpc_connectivity_state *current, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                       grpc_closure *notify) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p = (glb_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                 current, notify); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static const grpc_lb_policy_vtable glb_lb_policy_vtable = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    glb_destroy,     glb_shutdown,           glb_pick, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    glb_cancel_pick, glb_cancel_picks,       glb_ping_one, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    glb_exit_idle,   glb_check_connectivity, glb_notify_on_state_change}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void glb_factory_ref(grpc_lb_policy_factory *factory) {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void glb_factory_unref(grpc_lb_policy_factory *factory) {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                  grpc_lb_policy_factory *factory, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                  grpc_lb_policy_args *args) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *p = gpr_malloc(sizeof(*p)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(p, 0, sizeof(*p)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* all input addresses in args->addresses come from a resolver that claims 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * they are LB services. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * Create a client channel over them to communicate with a LB service */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->cc_factory = args->client_channel_factory; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(p->cc_factory != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (args->addresses->naddrs == 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* construct a target from the args->addresses, in the form 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * ipvX://ip1:port1,ip2:port2,... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * TODO(dgq): support mixed ip version */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char **addr_strs = gpr_malloc(sizeof(char *) * args->addresses->naddrs); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  addr_strs[0] = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_sockaddr_to_uri((const struct sockaddr *)&args->addresses->addrs[0]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (size_t i = 1; i < args->addresses->naddrs; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GPR_ASSERT(grpc_sockaddr_to_string( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   &addr_strs[i], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   (const struct sockaddr *)&args->addresses->addrs[i], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   true) == 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  size_t uri_path_len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char *target_uri_str = gpr_strjoin_sep( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (const char **)addr_strs, args->addresses->naddrs, ",", &uri_path_len); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* will pick using pick_first */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->lb_server_channel = grpc_client_channel_factory_create_channel( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      exec_ctx, p->cc_factory, target_uri_str, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_free(target_uri_str); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (size_t i = 0; i < args->addresses->naddrs; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_free(addr_strs[i]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_free(addr_strs); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (p->lb_server_channel == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_free(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  rr_connectivity_data *rr_connectivity = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_malloc(sizeof(rr_connectivity_data)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(rr_connectivity, 0, sizeof(rr_connectivity_data)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure_init(&rr_connectivity->on_change, rr_connectivity_changed, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    rr_connectivity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  rr_connectivity->p = p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->rr_connectivity = rr_connectivity; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_lb_policy_init(&p->base, &glb_lb_policy_vtable); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_init(&p->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE, "grpclb"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return &p->base; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static const grpc_lb_policy_factory_vtable glb_factory_vtable = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    glb_factory_ref, glb_factory_unref, glb_create, "grpclb"}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static grpc_lb_policy_factory glb_lb_policy_factory = {&glb_factory_vtable}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+grpc_lb_policy_factory *grpc_glb_lb_factory_create() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return &glb_lb_policy_factory; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Plugin registration */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void grpc_lb_policy_grpclb_init() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_register_lb_policy(grpc_glb_lb_factory_create()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_register_tracer("glb", &grpc_lb_glb_trace); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void grpc_lb_policy_grpclb_shutdown() {} 
			 |