| 
					
				 | 
			
			
				@@ -42,6 +42,7 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/surface/completion_queue.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include <grpc/support/alloc.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include <grpc/support/log.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <grpc/support/string_util.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include <assert.h> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include <stdio.h> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -98,6 +99,8 @@ typedef enum { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Status came from 'the wire' - or somewhere below the surface 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      layer */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   STATUS_FROM_WIRE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Status came from the server sending status */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  STATUS_FROM_SERVER_STATUS, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   STATUS_SOURCE_COUNT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } status_source; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -188,6 +191,7 @@ struct grpc_call { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				      and a strong upper bound of a count of masters to be calculated. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_uint8 request_set[GRPC_IOREQ_OP_COUNT]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_ioreq_data request_data[GRPC_IOREQ_OP_COUNT]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_uint32 request_flags[GRPC_IOREQ_OP_COUNT]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   reqinfo_master masters[GRPC_IOREQ_OP_COUNT]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Dynamic array of ioreq's that have completed: the count of 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -231,6 +235,7 @@ struct grpc_call { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_slice_buffer incoming_message; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_uint32 incoming_message_length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_uint32 incoming_message_flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_iomgr_closure destroy_closure; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -590,10 +595,18 @@ static void finish_live_ioreq_op(grpc_call *call, grpc_ioreq_op op, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             call->write_state = WRITE_STATE_WRITE_CLOSED; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case GRPC_IOREQ_SEND_STATUS: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details != 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            grpc_mdstr_unref( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         case GRPC_IOREQ_RECV_CLOSE: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         case GRPC_IOREQ_SEND_INITIAL_METADATA: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         case GRPC_IOREQ_SEND_TRAILING_METADATA: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        case GRPC_IOREQ_SEND_STATUS: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         case GRPC_IOREQ_SEND_CLOSE: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         case GRPC_IOREQ_RECV_STATUS: 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -677,7 +690,7 @@ static void call_on_done_send(void *pc, int success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void finish_message(grpc_call *call) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* TODO(ctiller): this could be a lot faster if coded directly */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_byte_buffer *byte_buffer = grpc_byte_buffer_create( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_byte_buffer *byte_buffer = grpc_raw_byte_buffer_create( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       call->incoming_message.slices, call->incoming_message.count); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_slice_buffer_reset_and_unref(&call->incoming_message); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -711,6 +724,7 @@ static int begin_message(grpc_call *call, grpc_begin_message msg) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } else if (msg.length > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     call->reading_message = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     call->incoming_message_length = msg.length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    call->incoming_message_flags = msg.flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     finish_message(call); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -800,7 +814,7 @@ static void call_on_done_recv(void *pc, int success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   unlock(call); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GRPC_CALL_INTERNAL_UNREF(call, "receiving", 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  GRPC_TIMER_BEGIN(GRPC_PTAG_CALL_ON_DONE_RECV, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GRPC_TIMER_END(GRPC_PTAG_CALL_ON_DONE_RECV, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static int prepare_application_metadata(grpc_call *call, size_t count, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -847,9 +861,9 @@ static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   size_t i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   switch (byte_buffer->type) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    case GRPC_BB_SLICE_BUFFER: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      for (i = 0; i < byte_buffer->data.slice_buffer.count; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        gpr_slice slice = byte_buffer->data.slice_buffer.slices[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    case GRPC_BB_RAW: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      for (i = 0; i < byte_buffer->data.raw.slice_buffer.count; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gpr_slice slice = byte_buffer->data.raw.slice_buffer.slices[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         gpr_slice_ref(slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         grpc_sopb_add_slice(sopb, slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -859,9 +873,9 @@ static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_ioreq_data data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_uint32 flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_metadata_batch mdb; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   size_t i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  char status_str[GPR_LTOA_MIN_BUFSIZE]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(op->send_ops == NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   switch (call->write_state) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -885,8 +899,9 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     case WRITE_STATE_STARTED: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       if (is_op_live(call, GRPC_IOREQ_SEND_MESSAGE)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         data = call->request_data[GRPC_IOREQ_SEND_MESSAGE]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        flags = call->request_flags[GRPC_IOREQ_SEND_MESSAGE]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         grpc_sopb_add_begin_message( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            &call->send_ops, grpc_byte_buffer_length(data.send_message), 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            &call->send_ops, grpc_byte_buffer_length(data.send_message), flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         copy_byte_buffer_to_stream_ops(data.send_message, &call->send_ops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         op->send_ops = &call->send_ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         call->last_send_contains |= 1 << GRPC_IOREQ_SEND_MESSAGE; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -905,13 +920,10 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           /* send status */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           /* TODO(ctiller): cache common status values */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           data = call->request_data[GRPC_IOREQ_SEND_STATUS]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          gpr_ltoa(data.send_status.code, status_str); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           grpc_metadata_batch_add_tail( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               &mdb, &call->status_link, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              grpc_mdelem_from_metadata_strings( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                  call->metadata_context, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                  grpc_mdstr_ref(grpc_channel_get_status_string(call->channel)), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                  grpc_mdstr_from_string(call->metadata_context, status_str))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              grpc_channel_get_reffed_status_elem(call->channel, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                  data.send_status.code)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           if (data.send_status.details) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             grpc_metadata_batch_add_tail( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 &mdb, &call->details_link, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -919,8 +931,9 @@ static int fill_send_ops(grpc_call *call, grpc_transport_op *op) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     call->metadata_context, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     grpc_mdstr_ref( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         grpc_channel_get_message_string(call->channel)), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    grpc_mdstr_from_string(call->metadata_context, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                           data.send_status.details))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    data.send_status.details)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            call->request_data[GRPC_IOREQ_SEND_STATUS].send_status.details = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           grpc_sopb_add_metadata(&call->send_ops, mdb); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1020,9 +1033,18 @@ static grpc_call_error start_ioreq(grpc_call *call, const grpc_ioreq *reqs, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                  GRPC_CALL_ERROR_INVALID_METADATA); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (op == GRPC_IOREQ_SEND_STATUS) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      set_status_code(call, STATUS_FROM_SERVER_STATUS, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      reqs[i].data.send_status.code); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (reqs[i].data.send_status.details) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        set_status_details(call, STATUS_FROM_SERVER_STATUS, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                           grpc_mdstr_ref(reqs[i].data.send_status.details)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     have_ops |= 1u << op; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     call->request_data[op] = data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    call->request_flags[op] = reqs[i].flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     call->request_set[op] = set; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1239,6 +1261,14 @@ static void finish_batch_with_close(grpc_call *call, int success, void *tag) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_cq_end_op(call->cq, tag, call, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int are_write_flags_valid(gpr_uint32 flags) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* check that only bits in GRPC_WRITE_(INTERNAL?)_USED_MASK are set */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const gpr_uint32 allowed_write_positions = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (GRPC_WRITE_USED_MASK | GRPC_WRITE_INTERNAL_USED_MASK); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const gpr_uint32 invalid_positions = ~allowed_write_positions; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return !(flags & invalid_positions); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                       size_t nops, void *tag) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_ioreq reqs[GRPC_IOREQ_OP_COUNT]; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1261,30 +1291,43 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     op = &ops[in]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     switch (op->op) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       case GRPC_OP_SEND_INITIAL_METADATA: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* Flag validation: currently allow no flags */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req = &reqs[out++]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->op = GRPC_IOREQ_SEND_INITIAL_METADATA; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->data.send_metadata.count = op->data.send_initial_metadata.count; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->data.send_metadata.metadata = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             op->data.send_initial_metadata.metadata; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        req->flags = op->flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       case GRPC_OP_SEND_MESSAGE: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!are_write_flags_valid(op->flags)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          return GRPC_CALL_ERROR_INVALID_FLAGS; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req = &reqs[out++]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->op = GRPC_IOREQ_SEND_MESSAGE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->data.send_message = op->data.send_message; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        req->flags = ops->flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       case GRPC_OP_SEND_CLOSE_FROM_CLIENT: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* Flag validation: currently allow no flags */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (!call->is_client) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           return GRPC_CALL_ERROR_NOT_ON_SERVER; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req = &reqs[out++]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->op = GRPC_IOREQ_SEND_CLOSE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        req->flags = op->flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       case GRPC_OP_SEND_STATUS_FROM_SERVER: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* Flag validation: currently allow no flags */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (call->is_client) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           return GRPC_CALL_ERROR_NOT_ON_CLIENT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req = &reqs[out++]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->op = GRPC_IOREQ_SEND_TRAILING_METADATA; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        req->flags = op->flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->data.send_metadata.count = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             op->data.send_status_from_server.trailing_metadata_count; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->data.send_metadata.metadata = 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1293,29 +1336,42 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->op = GRPC_IOREQ_SEND_STATUS; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->data.send_status.code = op->data.send_status_from_server.status; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->data.send_status.details = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            op->data.send_status_from_server.status_details; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            op->data.send_status_from_server.status_details != NULL 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ? grpc_mdstr_from_string( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      call->metadata_context, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      op->data.send_status_from_server.status_details) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                : NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req = &reqs[out++]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->op = GRPC_IOREQ_SEND_CLOSE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       case GRPC_OP_RECV_INITIAL_METADATA: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* Flag validation: currently allow no flags */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (!call->is_client) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           return GRPC_CALL_ERROR_NOT_ON_SERVER; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req = &reqs[out++]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->op = GRPC_IOREQ_RECV_INITIAL_METADATA; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->data.recv_metadata = op->data.recv_initial_metadata; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        req->flags = op->flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       case GRPC_OP_RECV_MESSAGE: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* Flag validation: currently allow no flags */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req = &reqs[out++]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->op = GRPC_IOREQ_RECV_MESSAGE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->data.recv_message = op->data.recv_message; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        req->flags = op->flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       case GRPC_OP_RECV_STATUS_ON_CLIENT: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* Flag validation: currently allow no flags */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (!call->is_client) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           return GRPC_CALL_ERROR_NOT_ON_SERVER; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req = &reqs[out++]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->op = GRPC_IOREQ_RECV_STATUS; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        req->flags = op->flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->data.recv_status.set_value = set_status_value_directly; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->data.recv_status.user_data = op->data.recv_status_on_client.status; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req = &reqs[out++]; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1333,8 +1389,11 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         finish_func = finish_batch_with_close; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       case GRPC_OP_RECV_CLOSE_ON_SERVER: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* Flag validation: currently allow no flags */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (op->flags != 0) return GRPC_CALL_ERROR_INVALID_FLAGS; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req = &reqs[out++]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->op = GRPC_IOREQ_RECV_STATUS; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        req->flags = op->flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->data.recv_status.set_value = set_cancelled_value; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         req->data.recv_status.user_data = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             op->data.recv_close_on_server.cancelled; 
			 |