@@ -76,6 +76,7 @@ static void encrypt_outgoing_tls(qdr_http2_connection_t *conn, qd_adaptor_buffer
76
76
bool write_buffers );
77
77
static bool schedule_activation (qdr_http2_connection_t * conn , qd_duration_t msec );
78
78
static void cancel_activation (qdr_http2_connection_t * conn );
79
+ static void close_connections (qdr_http2_connection_t * conn );
79
80
80
81
static void grant_read_buffers (qdr_http2_connection_t * conn , const char * msg )
81
82
{
@@ -87,6 +88,27 @@ static void grant_read_buffers(qdr_http2_connection_t *conn, const char *msg)
87
88
buffers );
88
89
}
89
90
91
+
92
+ static void free_stream_dispatcher_link (qdr_http2_connection_t * conn )
93
+ {
94
+ if (conn && conn -> stream_dispatcher ) {
95
+ qdr_http2_stream_data_t * stream_data = qdr_link_get_context (conn -> stream_dispatcher );
96
+ qd_log (LOG_HTTP_ADAPTOR , QD_LOG_DEBUG ,
97
+ "[C%" PRIu64 "] Detaching stream dispatcher link on egress connection, freed associated stream data" ,
98
+ conn -> conn_id );
99
+ if (stream_data ) {
100
+ qd_log (LOG_HTTP_ADAPTOR , QD_LOG_DEBUG , "[C%" PRIu64 "] Freeing stream_data (stream_dispatcher, free_stream_dispatcher_link) (%p)" , conn -> conn_id , (void * ) stream_data );
101
+ free_qdr_http2_stream_data_t (stream_data );
102
+ }
103
+ qdr_link_set_context (conn -> stream_dispatcher , 0 );
104
+ qdr_link_detach (conn -> stream_dispatcher , QD_CLOSED , 0 );
105
+
106
+
107
+ conn -> stream_dispatcher = 0 ;
108
+ conn -> stream_dispatcher_stream_data = 0 ;
109
+ }
110
+ }
111
+
90
112
/**
91
113
* If an ALPN protocol was detected by the TLS API, we make sure that the protocol matches the "h2" (short for http2) protocol.
92
114
* The connection is simply closed if any other protocol (other than h2) was detected.
@@ -416,6 +438,7 @@ void free_qdr_http2_connection(qdr_http2_connection_t* http_conn, bool on_shutdo
416
438
http_conn -> remote_address = 0 ;
417
439
}
418
440
if (http_conn -> activate_timer ) {
441
+ cancel_activation (http_conn );
419
442
qd_timer_free (http_conn -> activate_timer );
420
443
http_conn -> activate_timer = 0 ;
421
444
}
@@ -2878,7 +2901,6 @@ static void close_connections(qdr_http2_connection_t* conn)
2878
2901
conn -> conn_id );
2879
2902
conn -> dummy_link = 0 ;
2880
2903
}
2881
-
2882
2904
qdr_connection_set_context (conn -> qdr_conn , 0 );
2883
2905
if (conn -> qdr_conn ) {
2884
2906
qdr_connection_closed (conn -> qdr_conn );
@@ -2890,17 +2912,21 @@ static void close_connections(qdr_http2_connection_t* conn)
2890
2912
qdr_action_enqueue (http2_adaptor -> core , action );
2891
2913
}
2892
2914
2893
- static void clean_http2_conn (qdr_http2_connection_t * conn )
2915
+ static void clean_http2_conn (qdr_http2_connection_t * conn , bool free_buffers )
2894
2916
{
2895
2917
free_all_connection_streams (conn , false);
2896
-
2897
2918
//
2898
2919
// This closes the nghttp2 session. Next time when a new connection is opened, a new nghttp2 session
2899
2920
// will be created by calling nghttp2_session_client_new
2900
2921
//
2901
- nghttp2_session_del (conn -> session );
2902
- conn -> session = 0 ;
2903
- qd_adaptor_buffer_list_free_buffers (& conn -> out_buffs );
2922
+ if (conn -> session ) {
2923
+ nghttp2_session_del (conn -> session );
2924
+ conn -> session = 0 ;
2925
+ }
2926
+
2927
+ if (free_buffers ) {
2928
+ qd_adaptor_buffer_list_free_buffers (& conn -> out_buffs );
2929
+ }
2904
2930
2905
2931
// Free tls related stuff if need be.
2906
2932
if (conn -> tls ) {
@@ -2912,46 +2938,28 @@ static void clean_http2_conn(qdr_http2_connection_t* conn)
2912
2938
2913
2939
static void handle_disconnected (qdr_http2_connection_t * conn )
2914
2940
{
2915
- sys_mutex_lock (qd_server_get_activation_lock (http2_adaptor -> core -> qd -> server ));
2916
2941
if (conn -> pn_raw_conn ) {
2917
2942
qd_log (LOG_HTTP_ADAPTOR , QD_LOG_DEBUG ,
2918
2943
"[C%" PRIu64 "] handle_disconnected Setting conn->pn_raw_conn=0" , conn -> conn_id );
2919
2944
pn_raw_connection_set_context (conn -> pn_raw_conn , 0 );
2920
2945
conn -> pn_raw_conn = 0 ;
2921
2946
}
2922
-
2923
2947
if (conn -> ingress ) {
2924
- clean_http2_conn (conn );
2948
+ clean_http2_conn (conn , false );
2925
2949
close_connections (conn );
2926
2950
}
2927
2951
else {
2928
2952
if (conn -> stream_dispatcher ) {
2929
- qdr_http2_stream_data_t * stream_data = qdr_link_get_context (conn -> stream_dispatcher );
2930
- qd_log (LOG_HTTP_ADAPTOR , QD_LOG_DEBUG ,
2931
- "[C%" PRIu64 "] Detaching stream dispatcher link on egress connection, freed associated stream data" ,
2932
- conn -> conn_id );
2933
- qdr_link_detach (conn -> stream_dispatcher , QD_CLOSED , 0 );
2934
- qdr_link_set_context (conn -> stream_dispatcher , 0 );
2935
- conn -> stream_dispatcher = 0 ;
2936
- if (stream_data ) {
2937
- qd_log (LOG_HTTP_ADAPTOR , QD_LOG_DEBUG ,
2938
- "[C%" PRIu64 "] Freeing stream_data (stream_dispatcher, handle_disconnected) (%p)" ,
2939
- conn -> conn_id , (void * ) stream_data );
2940
- free_qdr_http2_stream_data_t (stream_data );
2941
- }
2942
- conn -> stream_dispatcher_stream_data = 0 ;
2943
-
2953
+ free_stream_dispatcher_link (conn );
2944
2954
}
2945
-
2946
2955
if (conn -> delete_egress_connections ) {
2947
- clean_http2_conn (conn );
2956
+ clean_http2_conn (conn , false );
2948
2957
close_connections (conn );
2949
2958
}
2950
2959
else {
2951
- clean_http2_conn (conn );
2960
+ clean_http2_conn (conn , true );
2952
2961
}
2953
2962
}
2954
- sys_mutex_unlock (qd_server_get_activation_lock (http2_adaptor -> core -> qd -> server ));
2955
2963
}
2956
2964
2957
2965
@@ -2965,24 +2973,6 @@ static void egress_conn_timer_handler(void *context)
2965
2973
// Protect with the lock when accessing conn->pn_raw_conn
2966
2974
sys_mutex_lock (qd_server_get_activation_lock (http2_adaptor -> core -> qd -> server ));
2967
2975
2968
- if (conn -> delete_egress_connections ) {
2969
- //
2970
- // The connector that this connection is associated with has been deleted.
2971
- // Free the associated connections
2972
- // It is ok to call qdr_connection_closed from this timer callback.
2973
- //
2974
- sys_mutex_unlock (qd_server_get_activation_lock (http2_adaptor -> core -> qd -> server ));
2975
- if (conn -> qdr_conn ) {
2976
- qdr_connection_closed (conn -> qdr_conn );
2977
- qd_connection_counter_dec (QD_PROTOCOL_HTTP2 );
2978
- conn -> qdr_conn = 0 ;
2979
- }
2980
-
2981
- if (conn -> connection_status == QD_CONNECTION_NEW )
2982
- free_qdr_http2_connection (conn , false);
2983
- return ;
2984
- }
2985
-
2986
2976
//
2987
2977
// If there is already a conn->pn_raw_conn, don't try to connect again.
2988
2978
//
@@ -3250,18 +3240,22 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
3250
3240
break ;
3251
3241
}
3252
3242
case PN_RAW_CONNECTION_DISCONNECTED : {
3243
+ //
3244
+ // Lock immediately since a delete connector can be called from a management thread
3245
+ // This same lock is used to lock the delete_connector function as well.
3246
+ //
3247
+ sys_mutex_lock (qd_server_get_activation_lock (http2_adaptor -> core -> qd -> server ));
3253
3248
conn -> connection_status = QD_CONNECTION_DISCONNECTED ;
3254
3249
qd_set_condition_on_vflow (conn -> pn_raw_conn , conn -> vflow );
3255
3250
if (!conn -> ingress ) {
3256
3251
conn -> initial_settings_frame_sent = false;
3257
- sys_mutex_lock ( qd_server_get_activation_lock ( http2_adaptor -> core -> qd -> server ));
3252
+
3258
3253
if (conn -> delete_egress_connections ) {
3259
- sys_mutex_unlock ( qd_server_get_activation_lock ( http2_adaptor -> core -> qd -> server ));
3254
+
3260
3255
// The egress connection has been deleted, cancel any pending timer
3261
3256
cancel_activation (conn );
3262
3257
}
3263
3258
else {
3264
- sys_mutex_unlock (qd_server_get_activation_lock (http2_adaptor -> core -> qd -> server ));
3265
3259
if (schedule_activation (conn , 2000 ))
3266
3260
qd_log (LOG_HTTP_ADAPTOR , QD_LOG_DEBUG ,
3267
3261
"[C%" PRIu64 "] Scheduling 2 second timer to reconnect to egress connection" ,
@@ -3275,6 +3269,7 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
3275
3269
"[C%" PRIu64 "] PN_RAW_CONNECTION_DISCONNECTED, ingress=%i, drained_buffers=%i" , conn -> conn_id ,
3276
3270
conn -> ingress , drained_buffers );
3277
3271
handle_disconnected (conn );
3272
+ sys_mutex_unlock (qd_server_get_activation_lock (http2_adaptor -> core -> qd -> server ));
3278
3273
break ;
3279
3274
}
3280
3275
case PN_RAW_CONNECTION_NEED_WRITE_BUFFERS : {
@@ -3299,8 +3294,9 @@ static void handle_connection_event(pn_event_t *e, qd_server_t *qd_server, void
3299
3294
conn -> conn_id );
3300
3295
handle_incoming_http (conn );
3301
3296
}
3302
-
3303
- while (qdr_connection_process (conn -> qdr_conn )) {}
3297
+ if (conn -> qdr_conn ) {
3298
+ while (qdr_connection_process (conn -> qdr_conn )) {}
3299
+ }
3304
3300
break ;
3305
3301
}
3306
3302
case PN_RAW_CONNECTION_READ : {
@@ -3381,14 +3377,33 @@ void qd_http2_delete_connector(qd_dispatch_t *qd, qd_http_connector_t *connector
3381
3377
//
3382
3378
// Deleting a connector must delete the corresponding qdr_connection_t and qdr_http2_connection_t objects also.
3383
3379
//
3380
+ // Lock immediately since a PN_RAW_CONNECTION_DISCONNECTED event can be raised from another thread.
3381
+ // This same lock is used to lock in the handler of PN_RAW_CONNECTION_DISCONNECTED as well.
3382
+ //
3383
+ sys_mutex_lock (qd_server_get_activation_lock (http2_adaptor -> core -> qd -> server ));
3384
3384
if (connector -> ctx ) {
3385
3385
qdr_connection_t * qdr_conn = (qdr_connection_t * ) connector -> ctx ;
3386
3386
qdr_http2_connection_t * http_conn = qdr_connection_get_context (qdr_conn );
3387
- sys_mutex_lock ( qd_server_get_activation_lock ( http2_adaptor -> core -> qd -> server ));
3387
+
3388
3388
http_conn -> delete_egress_connections = true;
3389
- sys_mutex_unlock (qd_server_get_activation_lock (http2_adaptor -> core -> qd -> server ));
3390
- qdr_core_close_connection (qdr_conn );
3389
+ //
3390
+ // The stream_dispatcher is a qdr_link. When a qdr_connection_t gets freed, it frees
3391
+ // all links in that connection. We want to explicitly detach and free the stream_dispatcher ourselves.
3392
+ // https://github.com/skupperproject/skupper-router/issues/1424
3393
+ //
3394
+ free_stream_dispatcher_link (http_conn );
3395
+ if (http_conn -> connection_status == QD_CONNECTION_DISCONNECTED ) {
3396
+ //
3397
+ // This connection has already received the PN_RAW_CONNECTION_DISCONNECTED event
3398
+ //
3399
+ clean_http2_conn (http_conn , false);
3400
+ close_connections (http_conn );
3401
+ }
3402
+ else {
3403
+ qdr_core_close_connection (qdr_conn );
3404
+ }
3391
3405
}
3406
+ sys_mutex_unlock (qd_server_get_activation_lock (http2_adaptor -> core -> qd -> server ));
3392
3407
qd_http_connector_decref (connector );
3393
3408
}
3394
3409
}
0 commit comments