| 
					
				 | 
			
			
				@@ -54,8 +54,16 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Putting a macro like this and littering the source file with #if is really 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   bad practice. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   TODO(jboeuf): refactor all the #if / #endif in a separate module. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#ifndef TSI_OPENSSL_ALPN_SUPPORT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define TSI_OPENSSL_ALPN_SUPPORT 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* TODO(jboeuf): I have not found a way to get this number dynamically from the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * SSL structure. This is what we would ultimately want though... */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   SSL structure. This is what we would ultimately want though... */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #define TSI_SSL_MAX_PROTECTION_OVERHEAD 100 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* --- Structure definitions. ---*/ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -70,6 +78,8 @@ struct tsi_ssl_handshaker_factory { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 typedef struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tsi_ssl_handshaker_factory base; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   SSL_CTX* ssl_context; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  unsigned char* alpn_protocol_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  size_t alpn_protocol_list_length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } tsi_ssl_client_handshaker_factory; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 typedef struct { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -841,7 +851,7 @@ static tsi_result ssl_handshaker_process_bytes_from_peer( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static tsi_result ssl_handshaker_extract_peer(tsi_handshaker* self, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                               tsi_peer* peer) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tsi_result result = TSI_OK; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  const unsigned char* alpn_selected; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const unsigned char* alpn_selected = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   unsigned int alpn_selected_len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   X509* peer_cert = SSL_get_peer_certificate(impl->ssl); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -850,7 +860,14 @@ static tsi_result ssl_handshaker_extract_peer(tsi_handshaker* self, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     X509_free(peer_cert); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (result != TSI_OK) return result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if TSI_OPENSSL_ALPN_SUPPORT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   SSL_get0_alpn_selected(impl->ssl, &alpn_selected, &alpn_selected_len); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif /* TSI_OPENSSL_ALPN_SUPPORT */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (alpn_selected == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* Try npn. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    SSL_get0_next_proto_negotiated(impl->ssl, &alpn_selected, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                   &alpn_selected_len); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (alpn_selected != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     size_t i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     tsi_peer_property* new_properties = 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1012,6 +1029,32 @@ static tsi_result create_tsi_ssl_handshaker(SSL_CTX* ctx, int is_client, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return TSI_OK; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int select_protocol_list(const unsigned char** out, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                unsigned char* outlen, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                const unsigned char* client_list, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                unsigned int client_list_len, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                const unsigned char* server_list, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                unsigned int server_list_len) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const unsigned char* client_current = client_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  while ((unsigned int)(client_current - client_list) < client_list_len) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    unsigned char client_current_len = *(client_current++); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const unsigned char* server_current = server_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    while ((server_current >= server_list) && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           (gpr_uintptr)(server_current - server_list) < server_list_len) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      unsigned char server_current_len = *(server_current++); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if ((client_current_len == server_current_len) && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          !memcmp(client_current, server_current, server_current_len)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        *out = server_current; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        *outlen = server_current_len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return SSL_TLSEXT_ERR_OK; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      server_current += server_current_len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    client_current += client_current_len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return SSL_TLSEXT_ERR_NOACK; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* --- tsi_ssl__client_handshaker_factory methods implementation. --- */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static tsi_result ssl_client_handshaker_factory_create_handshaker( 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1027,10 +1070,21 @@ static void ssl_client_handshaker_factory_destroy( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     tsi_ssl_handshaker_factory* self) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tsi_ssl_client_handshaker_factory* impl = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       (tsi_ssl_client_handshaker_factory*)self; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  SSL_CTX_free(impl->ssl_context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (impl->ssl_context != NULL) SSL_CTX_free(impl->ssl_context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   free(impl); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int client_handshaker_factory_npn_callback( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    SSL* ssl, unsigned char** out, unsigned char* outlen, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const unsigned char* in, unsigned int inlen, void* arg) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tsi_ssl_client_handshaker_factory* factory = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (tsi_ssl_client_handshaker_factory*)arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return select_protocol_list((const unsigned char**)out, outlen, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              factory->alpn_protocol_list, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              factory->alpn_protocol_list_length, in, inlen); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* --- tsi_ssl_server_handshaker_factory methods implementation. --- */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static tsi_result ssl_server_handshaker_factory_create_handshaker( 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1134,30 +1188,25 @@ static int ssl_server_handshaker_factory_servername_callback(SSL* ssl, int* ap, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return SSL_TLSEXT_ERR_ALERT_WARNING; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if TSI_OPENSSL_ALPN_SUPPORT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static int server_handshaker_factory_alpn_callback( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     SSL* ssl, const unsigned char** out, unsigned char* outlen, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     const unsigned char* in, unsigned int inlen, void* arg) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tsi_ssl_server_handshaker_factory* factory = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       (tsi_ssl_server_handshaker_factory*)arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  const unsigned char* client_current = in; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  while ((unsigned int)(client_current - in) < inlen) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    unsigned char client_current_len = *(client_current++); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    const unsigned char* server_current = factory->alpn_protocol_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    while ((server_current >= factory->alpn_protocol_list) && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-           (gpr_uintptr)(server_current - factory->alpn_protocol_list) < 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-           factory->alpn_protocol_list_length) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      unsigned char server_current_len = *(server_current++); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      if ((client_current_len == server_current_len) && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          !memcmp(client_current, server_current, server_current_len)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        *out = server_current; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        *outlen = server_current_len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        return SSL_TLSEXT_ERR_OK; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      server_current += server_current_len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    client_current += client_current_len; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  return SSL_TLSEXT_ERR_NOACK; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return select_protocol_list(out, outlen, in, inlen, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              factory->alpn_protocol_list, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              factory->alpn_protocol_list_length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif /* TSI_OPENSSL_ALPN_SUPPORT */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int server_handshaker_factory_npn_advertised_callback( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    SSL* ssl, const unsigned char** out, unsigned int* outlen, void* arg) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tsi_ssl_server_handshaker_factory* factory = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (tsi_ssl_server_handshaker_factory*)arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  *out = factory->alpn_protocol_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  *outlen = factory->alpn_protocol_list_length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return SSL_TLSEXT_ERR_OK; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* --- tsi_ssl_handshaker_factory constructors. --- */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1184,6 +1233,14 @@ tsi_result tsi_create_ssl_client_handshaker_factory( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     gpr_log(GPR_ERROR, "Could not create ssl context."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return TSI_INVALID_ARGUMENT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  impl = calloc(1, sizeof(tsi_ssl_client_handshaker_factory)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (impl == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    SSL_CTX_free(ssl_context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return TSI_OUT_OF_RESOURCES; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  impl->ssl_context = ssl_context; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   do { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     result = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         populate_ssl_context(ssl_context, pem_private_key, pem_private_key_size, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1197,41 +1254,33 @@ tsi_result tsi_create_ssl_client_handshaker_factory( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (num_alpn_protocols != 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      unsigned char* alpn_protocol_list = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      size_t alpn_protocol_list_length = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      int ssl_failed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       result = build_alpn_protocol_name_list( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           alpn_protocols, alpn_protocols_lengths, num_alpn_protocols, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          &alpn_protocol_list, &alpn_protocol_list_length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          &impl->alpn_protocol_list, &impl->alpn_protocol_list_length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       if (result != TSI_OK) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         gpr_log(GPR_ERROR, "Building alpn list failed with error %s.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 tsi_result_to_string(result)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        free(alpn_protocol_list); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      ssl_failed = SSL_CTX_set_alpn_protos(ssl_context, alpn_protocol_list, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                           alpn_protocol_list_length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      free(alpn_protocol_list); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      if (ssl_failed) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if TSI_OPENSSL_ALPN_SUPPORT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (SSL_CTX_set_alpn_protos(ssl_context, impl->alpn_protocol_list, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                  impl->alpn_protocol_list_length)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         gpr_log(GPR_ERROR, "Could not set alpn protocol list to context."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         result = TSI_INVALID_ARGUMENT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif /* TSI_OPENSSL_ALPN_SUPPORT */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      SSL_CTX_set_next_proto_select_cb( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ssl_context, client_handshaker_factory_npn_callback, impl); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } while (0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (result != TSI_OK) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    SSL_CTX_free(ssl_context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ssl_client_handshaker_factory_destroy(&impl->base); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* TODO(jboeuf): Add revocation verification. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  impl = calloc(1, sizeof(tsi_ssl_client_handshaker_factory)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (impl == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    SSL_CTX_free(ssl_context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return TSI_OUT_OF_RESOURCES; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  impl->ssl_context = ssl_context; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   impl->base.create_handshaker = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       ssl_client_handshaker_factory_create_handshaker; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   impl->base.destroy = ssl_client_handshaker_factory_destroy; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1322,8 +1371,13 @@ tsi_result tsi_create_ssl_server_handshaker_factory( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           impl->ssl_contexts[i], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           ssl_server_handshaker_factory_servername_callback); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       SSL_CTX_set_tlsext_servername_arg(impl->ssl_contexts[i], impl); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#if TSI_OPENSSL_ALPN_SUPPORT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       SSL_CTX_set_alpn_select_cb(impl->ssl_contexts[i], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                  server_handshaker_factory_alpn_callback, impl); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#endif /* TSI_OPENSSL_ALPN_SUPPORT */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      SSL_CTX_set_next_protos_advertised_cb( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          impl->ssl_contexts[i], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          server_handshaker_factory_npn_advertised_callback, impl); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } while (0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (result != TSI_OK) { 
			 |