@@ -292,6 +292,17 @@ struct aws_http_connection_manager {
292
292
*/
293
293
struct aws_task * cull_task ;
294
294
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 ;
295
306
};
296
307
297
308
struct aws_http_connection_manager_snapshot {
@@ -703,6 +714,13 @@ static void s_aws_http_connection_manager_finish_destroy(struct aws_http_connect
703
714
aws_http_proxy_config_destroy (manager -> proxy_config );
704
715
}
705
716
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
+
706
724
/*
707
725
* If this task exists then we are actually in the corresponding event loop running the final destruction task.
708
726
* 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(
819
837
return NULL ;
820
838
}
821
839
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
+
822
849
struct aws_http_connection_manager * manager =
823
850
aws_mem_calloc (allocator , 1 , sizeof (struct aws_http_connection_manager ));
824
851
if (manager == NULL ) {
@@ -896,6 +923,20 @@ struct aws_http_connection_manager *aws_http_connection_manager_new(
896
923
manager -> max_closed_streams = options -> max_closed_streams ;
897
924
manager -> http2_conn_manual_window_management = options -> http2_conn_manual_window_management ;
898
925
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
+
899
940
/* NOTHING can fail after here */
900
941
s_schedule_connection_culling (manager );
901
942
@@ -990,7 +1031,26 @@ static int s_aws_http_connection_manager_new_connection(struct aws_http_connecti
990
1031
options .host_name = aws_byte_cursor_from_string (manager -> host );
991
1032
options .port = manager -> port ;
992
1033
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 ;
994
1054
options .on_setup = s_aws_http_connection_manager_on_connection_setup ;
995
1055
options .on_shutdown = s_aws_http_connection_manager_on_connection_shutdown ;
996
1056
options .manual_window_management = manager -> enable_read_back_pressure ;
0 commit comments