@@ -292,6 +292,17 @@ struct aws_http_connection_manager {
292292 */
293293 struct aws_task * cull_task ;
294294 struct aws_event_loop * cull_event_loop ;
295+
296+ /*
297+ * An aws_array_list<struct aws_string *> of network interface names to distribute the connections using the
298+ * round-robin algorithm. We picked round-robin because it is trivial to implement and good enough. We can later
299+ * update to a more complex distribution algorithm if required.
300+ */
301+ struct aws_array_list network_interface_names ;
302+ /*
303+ * Current index in the network_interface_names array_list.
304+ */
305+ size_t network_interface_names_index ;
295306};
296307
297308struct aws_http_connection_manager_snapshot {
@@ -703,6 +714,13 @@ static void s_aws_http_connection_manager_finish_destroy(struct aws_http_connect
703714 aws_http_proxy_config_destroy (manager -> proxy_config );
704715 }
705716
717+ for (size_t i = 0 ; i < aws_array_list_length (& manager -> network_interface_names ); i ++ ) {
718+ struct aws_string * interface_name = NULL ;
719+ aws_array_list_get_at (& manager -> network_interface_names , & interface_name , i );
720+ aws_string_destroy (interface_name );
721+ }
722+ aws_array_list_clean_up (& manager -> network_interface_names );
723+
706724 /*
707725 * If this task exists then we are actually in the corresponding event loop running the final destruction task.
708726 * In that case, we've already cancelled this task and when you cancel, it runs synchronously. So in that
@@ -819,6 +837,15 @@ struct aws_http_connection_manager *aws_http_connection_manager_new(
819837 return NULL ;
820838 }
821839
840+ if (options -> socket_options -> network_interface_name [0 ] != '\0' && options -> num_network_interface_names > 0 ) {
841+ AWS_LOGF_ERROR (
842+ AWS_LS_HTTP_CONNECTION_MANAGER ,
843+ "Invalid options - socket_options.network_interface_name and network_interface_names_array cannot be both "
844+ "set." );
845+ aws_raise_error (AWS_ERROR_INVALID_ARGUMENT );
846+ return NULL ;
847+ }
848+
822849 struct aws_http_connection_manager * manager =
823850 aws_mem_calloc (allocator , 1 , sizeof (struct aws_http_connection_manager ));
824851 if (manager == NULL ) {
@@ -896,6 +923,20 @@ struct aws_http_connection_manager *aws_http_connection_manager_new(
896923 manager -> max_closed_streams = options -> max_closed_streams ;
897924 manager -> http2_conn_manual_window_management = options -> http2_conn_manual_window_management ;
898925
926+ manager -> network_interface_names_index = 0 ;
927+ if (options -> num_network_interface_names > 0 ) {
928+ aws_array_list_init_dynamic (
929+ & manager -> network_interface_names ,
930+ allocator ,
931+ options -> num_network_interface_names ,
932+ sizeof (struct aws_string * ));
933+ for (size_t i = 0 ; i < options -> num_network_interface_names ; i ++ ) {
934+ struct aws_byte_cursor interface_name = options -> network_interface_names_array [i ];
935+ struct aws_string * interface_name_str = aws_string_new_from_cursor (allocator , & interface_name );
936+ aws_array_list_push_back (& manager -> network_interface_names , & interface_name_str );
937+ }
938+ }
939+
899940 /* NOTHING can fail after here */
900941 s_schedule_connection_culling (manager );
901942
@@ -990,7 +1031,26 @@ static int s_aws_http_connection_manager_new_connection(struct aws_http_connecti
9901031 options .host_name = aws_byte_cursor_from_string (manager -> host );
9911032 options .port = manager -> port ;
9921033 options .initial_window_size = manager -> initial_window_size ;
993- options .socket_options = & manager -> socket_options ;
1034+ struct aws_socket_options socket_options = manager -> socket_options ;
1035+ if (aws_array_list_length (& manager -> network_interface_names )) {
1036+ struct aws_string * interface_name = NULL ;
1037+ aws_array_list_get_at (
1038+ & manager -> network_interface_names , & interface_name , manager -> network_interface_names_index );
1039+ manager -> network_interface_names_index =
1040+ (manager -> network_interface_names_index + 1 ) % aws_array_list_length (& manager -> network_interface_names );
1041+ #if defined(_MSC_VER )
1042+ # pragma warning(push)
1043+ # pragma warning(disable : 4996) /* allow strncpy() */
1044+ #endif
1045+ /* If the interface_name is too long or not null terminated, it will be caught in the `aws_socket_init` function
1046+ * so we don't need to worry about that here.*/
1047+ strncpy (
1048+ socket_options .network_interface_name , aws_string_c_str (interface_name ), AWS_NETWORK_INTERFACE_NAME_MAX );
1049+ #if defined(_MSC_VER )
1050+ # pragma warning(pop)
1051+ #endif
1052+ }
1053+ options .socket_options = & socket_options ;
9941054 options .on_setup = s_aws_http_connection_manager_on_connection_setup ;
9951055 options .on_shutdown = s_aws_http_connection_manager_on_connection_shutdown ;
9961056 options .manual_window_management = manager -> enable_read_back_pressure ;
0 commit comments