| 
					
				 | 
			
			
				@@ -43,30 +43,23 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * policy to select from this list of LB server backends. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * The first time the policy gets a request for a pick, a ping, or to exit the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * idle state, \a query_for_backends() is called. It creates an instance of \a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * lb_client_data, an internal struct meant to contain the data associated with 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * the internal communication with the LB server. This instance is created via 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * \a lb_client_data_create(). There, the call over lb_channel to pick-first 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * from {a1..an} is created, the \a LoadBalancingRequest message is assembled 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * and all necessary callbacks for the progress of the internal call configured. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * idle state, \a query_for_backends_locked() is called. This function sets up 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * and initiates the internal communication with the LB server. In particular, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * it's responsible for instantiating the internal *streaming* call to the LB 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * server (whichever address from {a1..an} pick-first chose). This call is 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * serviced by two callbacks, \a lb_on_server_status_received and \a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * lb_on_response_received. The former will be called when the call to the LB 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * server completes. This can happen if the LB server closes the connection or 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * if this policy itself cancels the call (for example because it's shutting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * down). If the internal call times out, the usual behavior of pick-first 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * applies, continuing to pick from the list {a1..an}. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * Back in \a query_for_backends(), the internal *streaming* call to the LB 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * server (whichever address from {a1..an} pick-first chose) is kicked off. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * It'll progress over the callbacks configured in \a lb_client_data_create() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * (see the field docstrings of \a lb_client_data for more details). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * If the call fails with UNIMPLEMENTED, the original call will also fail. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * There's a misconfiguration somewhere: at least one of {a1..an} isn't a LB 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * server, which contradicts the LB bit being set. If the internal call times 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * out, the usual behavior of pick-first applies, continuing to pick from the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * list {a1..an}. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * Upon sucesss, a \a LoadBalancingResponse is expected in \a res_recv_cb. An 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * invalid one results in the termination of the streaming call. A new streaming 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * call should be created if possible, failing the original call otherwise. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * For a valid \a LoadBalancingResponse, the server list of actual backends is 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * extracted. A Round Robin policy will be created from this list. There are two 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * possible scenarios: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Upon sucesss, the incoming \a LoadBalancingResponse is processed by \a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * res_recv. An invalid one results in the termination of the streaming call. A 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * new streaming call should be created if possible, failing the original call 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * otherwise. For a valid \a LoadBalancingResponse, the server list of actual 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * backends is extracted. A Round Robin policy will be created from this list. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * There are two possible scenarios: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * 1. This is the first server list received. There was no previous instance of 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  *    the Round Robin policy. \a rr_handover_locked() will instantiate the RR 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -84,10 +77,10 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * Once a RR policy instance is in place (and getting updated as described), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * calls to for a pick, a ping or a cancellation will be serviced right away by 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * forwarding them to the RR instance. Any time there's no RR policy available 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * (ie, right after the creation of the gRPCLB policy, if an empty serverlist 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * is received, etc), pick/ping requests are added to a list of pending 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * picks/pings to be flushed and serviced as part of \a rr_handover_locked() the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * moment the RR policy instance becomes available. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * (ie, right after the creation of the gRPCLB policy, if an empty serverlist is 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * received, etc), pick/ping requests are added to a list of pending picks/pings 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * to be flushed and serviced as part of \a rr_handover_locked() the moment the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * RR policy instance becomes available. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * \see https://github.com/grpc/grpc/blob/master/doc/load-balancing.md for the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * high level design and details. */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -120,12 +113,20 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/ext/lb_policy/grpclb/grpclb.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/ext/lb_policy/grpclb/load_balancer_api.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/channel/channel_args.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/lib/iomgr/sockaddr.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/iomgr/sockaddr_utils.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/lib/iomgr/timer.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/lib/support/backoff.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/support/string.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/surface/call.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/surface/channel.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/transport/static_metadata.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define BACKOFF_MULTIPLIER 1.6 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define BACKOFF_JITTER 0.2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define BACKOFF_MIN_SECONDS 10 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define BACKOFF_MAX_SECONDS 60 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 int grpc_lb_glb_trace = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* add lb_token of selected subchannel (address) to the call's initial 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -174,13 +175,12 @@ typedef struct wrapped_rr_closure_arg { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   wrapped_rr_closure_arg *wc_arg = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (wc_arg->rr_policy != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      gpr_log(GPR_INFO, "Unreffing RR (0x%" PRIxPTR ")", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              (intptr_t)wc_arg->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "wrapped_rr_closure"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(wc_arg->wrapped_closure != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_exec_ctx_sched(exec_ctx, wc_arg->wrapped_closure, GRPC_ERROR_REF(error), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (wc_arg->rr_policy != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* if target is NULL, no pick has been made by the RR policy (eg, all 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * addresses failed to connect). There won't be any user_data/token 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      * available */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -189,10 +189,12 @@ static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                     wc_arg->lb_token_mdelem_storage, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                     GRPC_MDELEM_REF(wc_arg->lb_token)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_INFO, "Unreffing RR (0x%" PRIxPTR ")", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (intptr_t)wc_arg->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "wrapped_rr_closure"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  GPR_ASSERT(wc_arg->wrapped_closure != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_exec_ctx_sched(exec_ctx, wc_arg->wrapped_closure, GRPC_ERROR_REF(error), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                      NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(wc_arg->free_when_done != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_free(wc_arg->free_when_done); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -264,7 +266,6 @@ static void add_pending_ping(pending_ping **root, grpc_closure *notify) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * glb_lb_policy 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 typedef struct rr_connectivity_data rr_connectivity_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-struct lb_client_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static const grpc_lb_policy_vtable glb_lb_policy_vtable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 typedef struct glb_lb_policy { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** base policy: must be first */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -296,20 +297,47 @@ typedef struct glb_lb_policy { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * response has arrived. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_grpclb_serverlist *serverlist; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** addresses from \a serverlist */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_lb_addresses *addresses; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** list of picks that are waiting on RR's policy connectivity */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   pending_pick *pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** list of pings that are waiting on RR's policy connectivity */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   pending_ping *pending_pings; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** client data associated with the LB server communication */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  struct lb_client_data *lb_client; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  bool shutting_down; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /************************************************************/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /*  client data associated with the LB server communication */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /************************************************************/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Status from the LB server has been received. This signals the end of the LB 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * call. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure lb_on_server_status_received; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* A response from the LB server has been received. Process it */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure lb_on_response_received; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_call *lb_call; /* streaming call to the LB server, */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_metadata_array lb_initial_metadata_recv; /* initial MD from LB server */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_metadata_array 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      lb_trailing_metadata_recv; /* trailing MD from LB server */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* what's being sent to the LB server. Note that its value may vary if the LB 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * server indicates a redirect. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_byte_buffer *lb_request_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* response the LB server, if any. Processed in lb_on_response_received() */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_byte_buffer *lb_response_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* call status code and details, set in lb_on_server_status_received() */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_status_code lb_call_status; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char *lb_call_status_details; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  size_t lb_call_status_details_capacity; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** LB call retry backoff state */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_backoff lb_call_backoff_state; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** for tracking of the RR connectivity */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  rr_connectivity_data *rr_connectivity; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** LB call retry timer */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_timer lb_call_retry_timer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } glb_lb_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* Keeps track and reacts to changes in connectivity of the RR instance */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -358,6 +386,28 @@ static int lb_token_cmp(void *token1, void *token2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static const grpc_lb_user_data_vtable lb_token_vtable = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     lb_token_copy, lb_token_destroy, lb_token_cmp}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void parse_server(const grpc_grpclb_server *server, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                         grpc_resolved_address *addr) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const uint16_t netorder_port = htons((uint16_t)server->port); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* the addresses are given in binary format (a in(6)_addr struct) in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * server->ip_address.bytes. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const grpc_grpclb_ip_address *ip = &server->ip_address; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(addr, 0, sizeof(*addr)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (ip->size == 4) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    addr->len = sizeof(struct sockaddr_in); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr->addr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    addr4->sin_family = AF_INET; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    memcpy(&addr4->sin_addr, ip->bytes, ip->size); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    addr4->sin_port = netorder_port; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else if (ip->size == 16) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    addr->len = sizeof(struct sockaddr_in6); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr->addr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    addr6->sin6_family = AF_INET; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    memcpy(&addr6->sin6_addr, ip->bytes, ip->size); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    addr6->sin6_port = netorder_port; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* Returns addresses extracted from \a serverlist. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static grpc_lb_addresses *process_serverlist( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     const grpc_grpclb_serverlist *serverlist) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -384,33 +434,18 @@ static grpc_lb_addresses *process_serverlist( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (!is_server_valid(serverlist->servers[sl_idx], sl_idx, false)) continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* address processing */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    const uint16_t netorder_port = htons((uint16_t)server->port); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /* the addresses are given in binary format (a in(6)_addr struct) in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * server->ip_address.bytes. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    const grpc_grpclb_ip_address *ip = &server->ip_address; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_resolved_address addr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    memset(&addr, 0, sizeof(addr)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (ip->size == 4) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      addr.len = sizeof(struct sockaddr_in); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr.addr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      addr4->sin_family = AF_INET; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      memcpy(&addr4->sin_addr, ip->bytes, ip->size); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      addr4->sin_port = netorder_port; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } else if (ip->size == 16) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      addr.len = sizeof(struct sockaddr_in6); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr.addr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      addr6->sin6_family = AF_INET; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      memcpy(&addr6->sin6_addr, ip->bytes, ip->size); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      addr6->sin6_port = netorder_port; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    parse_server(server, &addr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* lb token processing */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     void *user_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (server->has_load_balance_token) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      const size_t lb_token_size = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          GPR_ARRAY_SIZE(server->load_balance_token) - 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const size_t lb_token_max_length = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          GPR_ARRAY_SIZE(server->load_balance_token); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const size_t lb_token_length = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          strnlen(server->load_balance_token, lb_token_max_length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       grpc_mdstr *lb_token_mdstr = grpc_mdstr_from_buffer( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          (uint8_t *)server->load_balance_token, lb_token_size); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          (uint8_t *)server->load_balance_token, lb_token_length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       user_data = grpc_mdelem_from_metadata_strings(GRPC_MDSTR_LB_TOKEN, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                                     lb_token_mdstr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } else { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -427,7 +462,6 @@ static grpc_lb_addresses *process_serverlist( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ++addr_idx; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(addr_idx == num_valid); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return lb_addresses; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -448,7 +482,7 @@ static bool pick_from_internal_rr_locked( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       gpr_log(GPR_INFO, "Unreffing RR (0x%" PRIxPTR ")", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               (intptr_t)wc_arg->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "glb_pick"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "glb_pick_sync"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* add the load reporting initial metadata */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     initial_metadata_add_lb_token(pick_args->initial_metadata, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -461,7 +495,6 @@ static bool pick_from_internal_rr_locked( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * pending pick list inside the RR policy (glb_policy->rr_policy). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * Eventually, wrapped_on_complete will be called, which will -among other 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * things- add the LB token to the call's initial metadata */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return pick_done; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -470,54 +503,70 @@ static grpc_lb_policy *create_rr_locked( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     glb_lb_policy *glb_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(serverlist != NULL && serverlist->num_servers > 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (glb_policy->addresses != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /* dispose of the previous version */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    grpc_lb_addresses_destroy(glb_policy->addresses); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  glb_policy->addresses = process_serverlist(serverlist); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_lb_policy_args args; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   memset(&args, 0, sizeof(args)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   args.client_channel_factory = glb_policy->cc_factory; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_lb_addresses *addresses = process_serverlist(serverlist); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   // Replace the LB addresses in the channel args that we pass down to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   // the subchannel. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   static const char *keys_to_remove[] = {GRPC_ARG_LB_ADDRESSES}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  const grpc_arg arg = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      grpc_lb_addresses_create_channel_arg(glb_policy->addresses); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const grpc_arg arg = grpc_lb_addresses_create_channel_arg(addresses); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   args.args = grpc_channel_args_copy_and_add_and_remove( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       glb_policy->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_lb_policy *rr = grpc_lb_policy_create(exec_ctx, "round_robin", &args); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(rr != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_lb_addresses_destroy(addresses); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_channel_args_destroy(args.args); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return rr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void glb_rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                        grpc_error *error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* glb_policy->rr_policy may be NULL (initial handover) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void rr_handover_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                glb_lb_policy *glb_policy, grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(glb_policy->serverlist != NULL && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				              glb_policy->serverlist->num_servers > 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_log(GPR_INFO, "RR handover. Old RR: %p", (void *)glb_policy->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (glb_policy->rr_policy != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* if we are phasing out an existing RR instance, unref it. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "rr_handover"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   glb_policy->rr_policy = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       create_rr_locked(exec_ctx, glb_policy->serverlist, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    gpr_log(GPR_INFO, "Created RR policy (0x%" PRIxPTR ")", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            (intptr_t)glb_policy->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_log(GPR_INFO, "Created RR policy (%p)", (void *)glb_policy->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(glb_policy->rr_policy != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_pollset_set_add_pollset_set(exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                    glb_policy->rr_policy->interested_parties, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                    glb_policy->base.interested_parties); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  glb_policy->rr_connectivity->state = grpc_lb_policy_check_connectivity( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  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, glb_rr_connectivity_changed, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    rr_connectivity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  rr_connectivity->glb_policy = glb_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  rr_connectivity->state = grpc_lb_policy_check_connectivity( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       exec_ctx, glb_policy->rr_policy, &error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_lb_policy_notify_on_state_change( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      exec_ctx, glb_policy->rr_policy, &glb_policy->rr_connectivity->state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      &glb_policy->rr_connectivity->on_change); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                              glb_policy->rr_connectivity->state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                              GRPC_ERROR_REF(error), "rr_handover"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              rr_connectivity->state, GRPC_ERROR_REF(error), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              "rr_handover"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* subscribe */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "rr_connectivity_cb"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_lb_policy_notify_on_state_change(exec_ctx, glb_policy->rr_policy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                        &rr_connectivity->state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                        &rr_connectivity->on_change); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_lb_policy_exit_idle(exec_ctx, glb_policy->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* flush pending ops */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -551,35 +600,27 @@ static void rr_handover_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void glb_rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                         grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* If shutdown or error free the arg. Rely on the rest of the code to set the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * right grpclb status. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   rr_connectivity_data *rr_conn_data = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   glb_lb_policy *glb_policy = rr_conn_data->glb_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (rr_conn_data->state == GRPC_CHANNEL_SHUTDOWN) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (glb_policy->serverlist != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* a RR policy is shutting down but there's a serverlist available -> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-       * perform a handover */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      gpr_mu_lock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      rr_handover_locked(exec_ctx, glb_policy, error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      gpr_mu_unlock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* shutting down and no new serverlist available. Bail out. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      gpr_free(rr_conn_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (rr_conn_data->state != GRPC_CHANNEL_SHUTDOWN && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      !glb_policy->shutting_down) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_mu_lock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* RR not shutting down. Mimic the RR's policy state */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                rr_conn_data->state, GRPC_ERROR_REF(error), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                "rr_connectivity_cb"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* resubscribe. Reuse the "rr_connectivity_cb" weak ref. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_lb_policy_notify_on_state_change(exec_ctx, glb_policy->rr_policy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                          &rr_conn_data->state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                          &rr_conn_data->on_change); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_mu_unlock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (error == GRPC_ERROR_NONE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      gpr_mu_lock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* RR not shutting down. Mimic the RR's policy state */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                  rr_conn_data->state, GRPC_ERROR_REF(error), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                  "glb_rr_connectivity_changed"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* resubscribe */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      grpc_lb_policy_notify_on_state_change(exec_ctx, glb_policy->rr_policy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                            &rr_conn_data->state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                            &rr_conn_data->on_change); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      gpr_mu_unlock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } else { /* error */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      gpr_free(rr_conn_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              "rr_connectivity_cb"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_free(rr_conn_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -682,18 +723,11 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     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, glb_rr_connectivity_changed, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    rr_connectivity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  rr_connectivity->glb_policy = glb_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  glb_policy->rr_connectivity = rr_connectivity; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_lb_policy_init(&glb_policy->base, &glb_lb_policy_vtable); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_mu_init(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_connectivity_state_init(&glb_policy->state_tracker, GRPC_CHANNEL_IDLE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                "grpclb"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return &glb_policy->base; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -710,14 +744,13 @@ static void glb_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_grpclb_destroy_serverlist(glb_policy->serverlist); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_mu_destroy(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_lb_addresses_destroy(glb_policy->addresses); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_free(glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void lb_client_data_destroy(struct lb_client_data *lb_client); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void glb_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   glb_lb_policy *glb_policy = (glb_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_mu_lock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->shutting_down = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   pending_pick *pp = glb_policy->pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   glb_policy->pending_picks = NULL; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -741,15 +774,16 @@ static void glb_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (glb_policy->rr_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /* unsubscribe */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    grpc_lb_policy_notify_on_state_change( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        exec_ctx, glb_policy->rr_policy, NULL, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        &glb_policy->rr_connectivity->on_change); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "glb_shutdown"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  lb_client_data_destroy(glb_policy->lb_client); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  glb_policy->lb_client = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (glb_policy->started_picking) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (glb_policy->lb_call != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_call_cancel(glb_policy->lb_call, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* lb_on_server_status_received will pick up the cancellation and clean up 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_connectivity_state_set( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       exec_ctx, &glb_policy->state_tracker, GRPC_CHANNEL_SHUTDOWN, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -780,17 +814,12 @@ static void glb_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GRPC_ERROR_UNREF(error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static grpc_call *lb_client_data_get_call(struct lb_client_data *lb_client); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 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, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                              grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   glb_lb_policy *glb_policy = (glb_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_mu_lock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (glb_policy->lb_client != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /* cancel the call to the load balancer service, if any */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    grpc_call_cancel(lb_client_data_get_call(glb_policy->lb_client), NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   pending_pick *pp = glb_policy->pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   glb_policy->pending_picks = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   while (pp != NULL) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -810,18 +839,20 @@ static void glb_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GRPC_ERROR_UNREF(error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void query_for_backends(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               glb_lb_policy *glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void start_picking(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void query_for_backends_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                      glb_lb_policy *glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void start_picking_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                 glb_lb_policy *glb_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   glb_policy->started_picking = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  query_for_backends(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_backoff_reset(&glb_policy->lb_call_backoff_state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  query_for_backends_locked(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void glb_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   glb_lb_policy *glb_policy = (glb_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_mu_lock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (!glb_policy->started_picking) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    start_picking(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    start_picking_locked(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_mu_unlock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -847,8 +878,8 @@ static int glb_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (glb_policy->rr_policy != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      gpr_log(GPR_INFO, "about to PICK from 0x%" PRIxPTR "", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              (intptr_t)glb_policy->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_INFO, "grpclb %p about to PICK from RR %p", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (void *)glb_policy, (void *)glb_policy->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     GRPC_LB_POLICY_REF(glb_policy->rr_policy, "glb_pick"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -865,11 +896,17 @@ static int glb_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     pick_done = pick_from_internal_rr_locked(exec_ctx, glb_policy->rr_policy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                              pick_args, target, wc_arg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_DEBUG, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              "No RR policy in grpclb instance %p. Adding to grpclb's pending " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              "picks", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (void *)(glb_policy)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     add_pending_pick(&glb_policy->pending_picks, pick_args, target, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                      on_complete); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (!glb_policy->started_picking) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      start_picking(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      start_picking_locked(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     pick_done = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -898,7 +935,7 @@ static void glb_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     add_pending_ping(&glb_policy->pending_pings, closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (!glb_policy->started_picking) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      start_picking(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      start_picking_locked(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_mu_unlock(&glb_policy->mu); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -916,250 +953,182 @@ static void glb_notify_on_state_change(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_mu_unlock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * lb_client_data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * Used internally for the client call to the LB */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-typedef struct lb_client_data { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  gpr_mu mu; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* called once initial metadata's been sent */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_closure md_sent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* called once the LoadBalanceRequest has been sent to the LB server. See 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * src/proto/grpc/.../load_balancer.proto */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_closure req_sent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* A response from the LB server has been received (or error). Process it */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_closure res_rcvd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* After the client has sent a close to the LB server */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_closure close_sent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* ... and the status from the LB server has been received */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_closure srv_status_rcvd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_call *lb_call;    /* streaming call to the LB server, */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  gpr_timespec deadline; /* for the streaming call to the LB server */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_metadata_array initial_metadata_recv;  /* initial MD from LB server */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_metadata_array trailing_metadata_recv; /* trailing MD from LB server */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* what's being sent to the LB server. Note that its value may vary if the LB 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * server indicates a redirect. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_byte_buffer *request_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* response from the LB server, if any. Processed in res_recv_cb() */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_byte_buffer *response_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* the call's status and status detailset in srv_status_rcvd_cb() */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_status_code status; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  char *status_details; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  size_t status_details_capacity; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* pointer back to the enclosing policy */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  glb_lb_policy *glb_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} lb_client_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void md_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void req_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void close_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                          grpc_error *error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void srv_status_rcvd_cb(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               grpc_error *error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static lb_client_data *lb_client_data_create(glb_lb_policy *glb_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void lb_on_server_status_received(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                         grpc_error *error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void lb_on_response_received(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    grpc_error *error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void lb_call_init(glb_lb_policy *glb_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(glb_policy->server_name != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(glb_policy->server_name[0] != '\0'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  lb_client_data *lb_client = gpr_malloc(sizeof(lb_client_data)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  memset(lb_client, 0, sizeof(lb_client_data)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  gpr_mu_init(&lb_client->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_closure_init(&lb_client->md_sent, md_sent_cb, lb_client); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_closure_init(&lb_client->req_sent, req_sent_cb, lb_client); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_closure_init(&lb_client->res_rcvd, res_recv_cb, lb_client); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_closure_init(&lb_client->close_sent, close_sent_cb, lb_client); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_closure_init(&lb_client->srv_status_rcvd, srv_status_rcvd_cb, lb_client); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  lb_client->deadline = glb_policy->deadline; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Note the following LB call progresses every time there's activity in \a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * glb_policy->base.interested_parties, which is comprised of the polling 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * entities from \a client_channel. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  lb_client->lb_call = grpc_channel_create_pollset_set_call( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->lb_call = grpc_channel_create_pollset_set_call( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       glb_policy->lb_channel, NULL, GRPC_PROPAGATE_DEFAULTS, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       glb_policy->base.interested_parties, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       "/grpc.lb.v1.LoadBalancer/BalanceLoad", glb_policy->server_name, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      lb_client->deadline, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      glb_policy->deadline, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_metadata_array_init(&lb_client->initial_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_metadata_array_init(&lb_client->trailing_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_metadata_array_init(&glb_policy->lb_initial_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_metadata_array_init(&glb_policy->lb_trailing_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_grpclb_request *request = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       grpc_grpclb_request_create(glb_policy->server_name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_slice request_payload_slice = grpc_grpclb_request_encode(request); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  lb_client->request_payload = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->lb_request_payload = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       grpc_raw_byte_buffer_create(&request_payload_slice, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_slice_unref(request_payload_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_grpclb_request_destroy(request); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  lb_client->status_details = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  lb_client->status_details_capacity = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  lb_client->glb_policy = glb_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  return lb_client; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->lb_call_status_details = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->lb_call_status_details_capacity = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure_init(&glb_policy->lb_on_server_status_received, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    lb_on_server_status_received, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure_init(&glb_policy->lb_on_response_received, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    lb_on_response_received, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_backoff_init(&glb_policy->lb_call_backoff_state, BACKOFF_MULTIPLIER, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   BACKOFF_JITTER, BACKOFF_MIN_SECONDS * 1000, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                   BACKOFF_MAX_SECONDS * 1000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void lb_client_data_destroy(lb_client_data *lb_client) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_call_destroy(lb_client->lb_call); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_metadata_array_destroy(&lb_client->initial_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_metadata_array_destroy(&lb_client->trailing_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void lb_call_destroy(glb_lb_policy *glb_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(glb_policy->lb_call != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_call_destroy(glb_policy->lb_call); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->lb_call = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_byte_buffer_destroy(lb_client->request_payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_metadata_array_destroy(&glb_policy->lb_initial_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_metadata_array_destroy(&glb_policy->lb_trailing_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  gpr_free(lb_client->status_details); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  gpr_mu_destroy(&lb_client->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  gpr_free(lb_client); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static grpc_call *lb_client_data_get_call(lb_client_data *lb_client) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  return lb_client->lb_call; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_byte_buffer_destroy(glb_policy->lb_request_payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_free(glb_policy->lb_call_status_details); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * Auxiliary functions and LB client callbacks. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void query_for_backends(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               glb_lb_policy *glb_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void query_for_backends_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                      glb_lb_policy *glb_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(glb_policy->lb_channel != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lb_call_init(glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_log(GPR_INFO, "Query for backends (grpclb: %p, lb_call: %p)", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (void *)glb_policy, (void *)glb_policy->lb_call); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(glb_policy->lb_call != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  glb_policy->lb_client = lb_client_data_create(glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_call_error call_error; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_op ops[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_op ops[4]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   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++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  call_error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      exec_ctx, glb_policy->lb_client->lb_call, ops, (size_t)(op - ops), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      &glb_policy->lb_client->md_sent); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  GPR_ASSERT(GRPC_CALL_OK == call_error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  op = ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  op->data.recv_status_on_client.trailing_metadata = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      &glb_policy->lb_client->trailing_metadata_recv; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  op->data.recv_status_on_client.status = &glb_policy->lb_client->status; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  op->data.recv_status_on_client.status_details = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      &glb_policy->lb_client->status_details; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  op->data.recv_status_on_client.status_details_capacity = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      &glb_policy->lb_client->status_details_capacity; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->op = GRPC_OP_RECV_INITIAL_METADATA; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.recv_initial_metadata = &glb_policy->lb_initial_metadata_recv; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  call_error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      exec_ctx, glb_policy->lb_client->lb_call, ops, (size_t)(op - ops), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      &glb_policy->lb_client->srv_status_rcvd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  GPR_ASSERT(GRPC_CALL_OK == call_error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void md_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  lb_client_data *lb_client = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  GPR_ASSERT(lb_client->lb_call); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_op ops[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  memset(ops, 0, sizeof(ops)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_op *op = ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(glb_policy->lb_request_payload != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->op = GRPC_OP_SEND_MESSAGE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  op->data.send_message = lb_client->request_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.send_message = glb_policy->lb_request_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_call_error call_error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      &lb_client->req_sent); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  GPR_ASSERT(GRPC_CALL_OK == call_error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void req_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  lb_client_data *lb_client = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  GPR_ASSERT(lb_client->lb_call); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_op ops[2]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  memset(ops, 0, sizeof(ops)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_op *op = ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  op->op = GRPC_OP_RECV_INITIAL_METADATA; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  op->data.recv_initial_metadata = &lb_client->initial_metadata_recv; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.recv_status_on_client.trailing_metadata = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      &glb_policy->lb_trailing_metadata_recv; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.recv_status_on_client.status = &glb_policy->lb_call_status; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.recv_status_on_client.status_details = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      &glb_policy->lb_call_status_details; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.recv_status_on_client.status_details_capacity = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      &glb_policy->lb_call_status_details_capacity; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* take a weak ref (won't prevent calling of \a glb_shutdown if the strong ref 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * count goes to zero) to be unref'd in lb_on_server_status_received */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_server_status_received"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  call_error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      &glb_policy->lb_on_server_status_received); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(GRPC_CALL_OK == call_error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op = ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->op = GRPC_OP_RECV_MESSAGE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  op->data.recv_message = &lb_client->response_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op->data.recv_message = &glb_policy->lb_response_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_call_error call_error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      &lb_client->res_rcvd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* take another weak ref to be unref'd in lb_on_response_received */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_response_received"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  call_error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      &glb_policy->lb_on_response_received); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(GRPC_CALL_OK == call_error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  lb_client_data *lb_client = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void lb_on_response_received(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *glb_policy = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_op ops[2]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   memset(ops, 0, sizeof(ops)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_op *op = ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (lb_client->response_payload != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (glb_policy->lb_response_payload != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_backoff_reset(&glb_policy->lb_call_backoff_state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* Received data from the LB server. Look inside 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * lb_client->response_payload, for a serverlist. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * glb_policy->lb_response_payload, for a serverlist. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_byte_buffer_reader bbr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    grpc_byte_buffer_reader_init(&bbr, lb_client->response_payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_byte_buffer_reader_init(&bbr, glb_policy->lb_response_payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     gpr_slice response_slice = grpc_byte_buffer_reader_readall(&bbr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    grpc_byte_buffer_destroy(lb_client->response_payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_byte_buffer_destroy(glb_policy->lb_response_payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_grpclb_serverlist *serverlist = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         grpc_grpclb_response_parse_serverlist(response_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (serverlist != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      GPR_ASSERT(glb_policy->lb_call != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       gpr_slice_unref(response_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         gpr_log(GPR_INFO, "Serverlist with %lu servers received", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 (unsigned long)serverlist->num_servers); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (size_t i = 0; i < serverlist->num_servers; ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          grpc_resolved_address addr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          parse_server(serverlist->servers[i], &addr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          char *ipport; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          grpc_sockaddr_to_string(&ipport, &addr, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          gpr_log(GPR_INFO, "Serverlist[%lu]: %s", (unsigned long)i, ipport); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          gpr_free(ipport); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       /* update serverlist */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       if (serverlist->num_servers > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        gpr_mu_lock(&lb_client->glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if (grpc_grpclb_serverlist_equals(lb_client->glb_policy->serverlist, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                          serverlist)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gpr_mu_lock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (grpc_grpclb_serverlist_equals(glb_policy->serverlist, serverlist)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             gpr_log(GPR_INFO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     "Incoming server list identical to current, ignoring."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } else { /* new serverlist */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          if (lb_client->glb_policy->serverlist != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (glb_policy->serverlist != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             /* dispose of the old serverlist */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            grpc_grpclb_destroy_serverlist(lb_client->glb_policy->serverlist); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            grpc_grpclb_destroy_serverlist(glb_policy->serverlist); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           /* and update the copy in the glb_lb_policy instance */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          lb_client->glb_policy->serverlist = serverlist; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if (lb_client->glb_policy->rr_policy == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          /* initial "handover", in this case from a null RR policy, meaning 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-           * it'll just create the first RR policy instance */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          rr_handover_locked(exec_ctx, lb_client->glb_policy, error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          /* unref the RR policy, eventually leading to its substitution with a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-           * new one constructed from the received serverlist (see 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-           * glb_rr_connectivity_changed) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          GRPC_LB_POLICY_UNREF(exec_ctx, lb_client->glb_policy->rr_policy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               "serverlist_received"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          glb_policy->serverlist = serverlist; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          rr_handover_locked(exec_ctx, glb_policy, error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        gpr_mu_unlock(&lb_client->glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gpr_mu_unlock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           gpr_log(GPR_INFO, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1167,60 +1136,94 @@ static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                   "response with > 0 servers is received"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { /* serverlist == NULL */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_ERROR, "Invalid LB response received: '%s'. Ignoring.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              gpr_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_slice_unref(response_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!glb_policy->shutting_down) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       /* keep listening for serverlist updates */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       op->op = GRPC_OP_RECV_MESSAGE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      op->data.recv_message = &lb_client->response_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      op->data.recv_message = &glb_policy->lb_response_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* reuse the "lb_on_response_received" weak ref taken in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * query_for_backends_locked() */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       const grpc_call_error call_error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          &lb_client->res_rcvd); /* loop */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          &glb_policy->lb_on_response_received); /* loop */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       GPR_ASSERT(GRPC_CALL_OK == call_error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GPR_ASSERT(serverlist == NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    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 call_error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        &lb_client->close_sent); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GPR_ASSERT(GRPC_CALL_OK == call_error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { /* empty payload: call cancelled. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           /* dispose of the "lb_on_response_received" weak ref taken in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            * query_for_backends_locked() and reused in every reception loop */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              "lb_on_response_received_empty_payload"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* 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, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                          grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    gpr_log(GPR_INFO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            "Close from LB client sent. Waiting from server status now"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void lb_call_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                   grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *glb_policy = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!glb_policy->shutting_down) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_INFO, "Restaring call to LB server (grpclb %p)", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (void *)glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GPR_ASSERT(glb_policy->lb_call == NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    query_for_backends_locked(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            "grpclb_on_retry_timer"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void srv_status_rcvd_cb(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  lb_client_data *lb_client = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void lb_on_server_status_received(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                         grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *glb_policy = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(glb_policy->lb_call != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    gpr_log(GPR_INFO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            "status from lb server received. Status = %d, Details = '%s', " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            "Capacity " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            "= %lu", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            lb_client->status, lb_client->status_details, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            (unsigned long)lb_client->status_details_capacity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_log(GPR_DEBUG, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "Status from LB server received. Status = %d, Details = '%s', " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "(call: %p)", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            glb_policy->lb_call_status, glb_policy->lb_call_status_details, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (void *)glb_policy->lb_call); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* We need to performe cleanups no matter what. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lb_call_destroy(glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!glb_policy->shutting_down) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* if we aren't shutting down, restart the LB client call after some time */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_timespec next_try = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gpr_backoff_step(&glb_policy->lb_call_backoff_state, now); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_DEBUG, "Connection to LB server lost (grpclb: %p)...", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (void *)glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_timespec timeout = gpr_time_sub(next_try, now); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (gpr_time_cmp(timeout, gpr_time_0(timeout.clock_type)) > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gpr_log(GPR_DEBUG, "... retrying in %" PRId64 ".%09d seconds.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                timeout.tv_sec, timeout.tv_nsec); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gpr_log(GPR_DEBUG, "... retrying immediately."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "grpclb_retry_timer"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_timer_init(exec_ctx, &glb_policy->lb_call_retry_timer, next_try, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    lb_call_on_retry_timer, glb_policy, now); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* TODO(dgq): deal with stream termination properly (fire up another one? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * fail the original call?) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&glb_policy->mu); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            "lb_on_server_status_received"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* Code wiring the policy with the rest of the core */ 
			 |