@@ -253,7 +253,7 @@ impl Builder {
253
253
/// Sets the [ALPN] protocols that this endpoint will accept on incoming connections.
254
254
///
255
255
/// Not setting this will still allow creating connections, but to accept incoming
256
- /// connections the [ALPN] must be set.
256
+ /// connections at least one [ALPN] must be set.
257
257
///
258
258
/// [ALPN]: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
259
259
pub fn alpns ( mut self , alpn_protocols : Vec < Vec < u8 > > ) -> Self {
@@ -752,7 +752,8 @@ impl Endpoint {
752
752
"Attempting connection..."
753
753
) ;
754
754
let client_config = {
755
- let alpn_protocols = vec ! [ alpn. to_vec( ) ] ;
755
+ let mut alpn_protocols = vec ! [ alpn. to_vec( ) ] ;
756
+ alpn_protocols. extend ( options. additional_alpns ) ;
756
757
let quic_client_config = self . static_config . tls_auth . make_client_config (
757
758
& self . static_config . secret_key ,
758
759
node_id,
@@ -1263,6 +1264,7 @@ impl Endpoint {
1263
1264
#[ derive( Default , Debug , Clone ) ]
1264
1265
pub struct ConnectOptions {
1265
1266
transport_config : Option < Arc < TransportConfig > > ,
1267
+ additional_alpns : Vec < Vec < u8 > > ,
1266
1268
}
1267
1269
1268
1270
impl ConnectOptions {
@@ -1279,6 +1281,31 @@ impl ConnectOptions {
1279
1281
self . transport_config = Some ( transport_config) ;
1280
1282
self
1281
1283
}
1284
+
1285
+ /// Sets [ALPN] identifiers that should be signaled as supported on connection, *in
1286
+ /// addition* to the main [ALPN] identifier used in [`Endpoint::connect_with_opts`].
1287
+ ///
1288
+ /// This allows connecting to servers that may only support older versions of your
1289
+ /// protocol. In this case, you would add the older [ALPN] identifiers with this
1290
+ /// function.
1291
+ ///
1292
+ /// You'll know the final negotiated [ALPN] identifier once your connection was
1293
+ /// established using [`Connection::alpn`], or even slightly earlier in the
1294
+ /// handshake by using [`Connecting::alpn`].
1295
+ /// The negotiated [ALPN] identifier may be any of the [ALPN] identifiers in this
1296
+ /// list or the main [ALPN] used in [`Endpoint::connect_with_opts`].
1297
+ ///
1298
+ /// The [ALPN] identifier order on the connect side doesn't matter, since it's the
1299
+ /// accept side that determines the protocol.
1300
+ ///
1301
+ /// For setting the supported [ALPN] identifiers on the accept side, see the endpoint
1302
+ /// builder's [`Builder::alpns`] function.
1303
+ ///
1304
+ /// [ALPN]: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
1305
+ pub fn with_additional_alpns ( mut self , alpns : Vec < Vec < u8 > > ) -> Self {
1306
+ self . additional_alpns = alpns;
1307
+ self
1308
+ }
1282
1309
}
1283
1310
1284
1311
/// Future produced by [`Endpoint::accept`].
@@ -2779,4 +2806,102 @@ mod tests {
2779
2806
2780
2807
Ok ( ( ) )
2781
2808
}
2809
+
2810
+ /// Configures the accept side to take `accept_alpns` ALPNs, then connects to it with `primary_connect_alpn`
2811
+ /// with `secondary_connect_alpns` set, and finally returns the negotiated ALPN.
2812
+ async fn alpn_connection_test (
2813
+ accept_alpns : Vec < Vec < u8 > > ,
2814
+ primary_connect_alpn : & [ u8 ] ,
2815
+ secondary_connect_alpns : Vec < Vec < u8 > > ,
2816
+ ) -> testresult:: TestResult < Option < Vec < u8 > > > {
2817
+ let client = Endpoint :: builder ( )
2818
+ . relay_mode ( RelayMode :: Disabled )
2819
+ . bind ( )
2820
+ . await ?;
2821
+ let server = Endpoint :: builder ( )
2822
+ . relay_mode ( RelayMode :: Disabled )
2823
+ . alpns ( accept_alpns)
2824
+ . bind ( )
2825
+ . await ?;
2826
+ let server_addr = server. node_addr ( ) . await ?;
2827
+ let server_task = tokio:: spawn ( {
2828
+ let server = server. clone ( ) ;
2829
+ async move {
2830
+ let incoming = server. accept ( ) . await . unwrap ( ) ;
2831
+ let conn = incoming. await ?;
2832
+ conn. close ( 0u32 . into ( ) , b"bye!" ) ;
2833
+ testresult:: TestResult :: Ok ( conn. alpn ( ) )
2834
+ }
2835
+ } ) ;
2836
+
2837
+ let conn = client
2838
+ . connect_with_opts (
2839
+ server_addr,
2840
+ primary_connect_alpn,
2841
+ ConnectOptions :: new ( ) . with_additional_alpns ( secondary_connect_alpns) ,
2842
+ )
2843
+ . await ?;
2844
+ let conn = conn. await ?;
2845
+ let client_alpn = conn. alpn ( ) ;
2846
+ conn. closed ( ) . await ;
2847
+ client. close ( ) . await ;
2848
+ server. close ( ) . await ;
2849
+
2850
+ let server_alpn = server_task. await ??;
2851
+
2852
+ assert_eq ! ( client_alpn, server_alpn) ;
2853
+
2854
+ Ok ( server_alpn)
2855
+ }
2856
+
2857
+ #[ tokio:: test]
2858
+ #[ traced_test]
2859
+ async fn connect_multiple_alpn_negotiated ( ) -> testresult:: TestResult {
2860
+ const ALPN_ONE : & [ u8 ] = b"alpn/1" ;
2861
+ const ALPN_TWO : & [ u8 ] = b"alpn/2" ;
2862
+
2863
+ assert_eq ! (
2864
+ alpn_connection_test(
2865
+ // Prefer version 2 over version 1 on the accept side
2866
+ vec![ ALPN_TWO . to_vec( ) , ALPN_ONE . to_vec( ) ] ,
2867
+ ALPN_TWO ,
2868
+ vec![ ALPN_ONE . to_vec( ) ] ,
2869
+ )
2870
+ . await ?,
2871
+ Some ( ALPN_TWO . to_vec( ) ) ,
2872
+ "accept side prefers version 2 over 1"
2873
+ ) ;
2874
+
2875
+ assert_eq ! (
2876
+ alpn_connection_test(
2877
+ // Only support the old version
2878
+ vec![ ALPN_ONE . to_vec( ) ] ,
2879
+ ALPN_TWO ,
2880
+ vec![ ALPN_ONE . to_vec( ) ] ,
2881
+ )
2882
+ . await ?,
2883
+ Some ( ALPN_ONE . to_vec( ) ) ,
2884
+ "accept side only supports the old version"
2885
+ ) ;
2886
+
2887
+ assert_eq ! (
2888
+ alpn_connection_test(
2889
+ vec![ ALPN_TWO . to_vec( ) , ALPN_ONE . to_vec( ) ] ,
2890
+ ALPN_ONE ,
2891
+ vec![ ALPN_TWO . to_vec( ) ] ,
2892
+ )
2893
+ . await ?,
2894
+ Some ( ALPN_TWO . to_vec( ) ) ,
2895
+ "connect side ALPN order doesn't matter"
2896
+ ) ;
2897
+
2898
+ assert_eq ! (
2899
+ alpn_connection_test( vec![ ALPN_TWO . to_vec( ) , ALPN_ONE . to_vec( ) ] , ALPN_ONE , vec![ ] , )
2900
+ . await ?,
2901
+ Some ( ALPN_ONE . to_vec( ) ) ,
2902
+ "connect side only supports the old version"
2903
+ ) ;
2904
+
2905
+ Ok ( ( ) )
2906
+ }
2782
2907
}
0 commit comments