@@ -55,6 +55,7 @@ struct aws_websocket {
5555 struct aws_channel_task shutdown_channel_task ;
5656 struct aws_channel_task increment_read_window_task ;
5757 struct aws_channel_task waiting_on_payload_stream_task ;
58+ struct aws_channel_task close_timeout_task ;
5859 bool is_server ;
5960
6061 /* Data that should only be accessed from the websocket's channel thread. */
@@ -183,6 +184,7 @@ static void s_move_synced_data_to_thread_task(struct aws_channel_task *task, voi
183184static void s_increment_read_window_task (struct aws_channel_task * task , void * arg , enum aws_task_status status );
184185static void s_shutdown_channel_task (struct aws_channel_task * task , void * arg , enum aws_task_status status );
185186static void s_waiting_on_payload_stream_task (struct aws_channel_task * task , void * arg , enum aws_task_status status );
187+ static void s_close_timeout_task (struct aws_channel_task * task , void * arg , enum aws_task_status status );
186188static void s_schedule_channel_shutdown (struct aws_websocket * websocket , int error_code );
187189static void s_shutdown_due_to_write_err (struct aws_websocket * websocket , int error_code );
188190static void s_shutdown_due_to_read_err (struct aws_websocket * websocket , int error_code );
@@ -291,6 +293,7 @@ struct aws_websocket *aws_websocket_handler_new(const struct aws_websocket_handl
291293 s_waiting_on_payload_stream_task ,
292294 websocket ,
293295 "websocket_waiting_on_payload_stream" );
296+ aws_channel_task_init (& websocket -> close_timeout_task , s_close_timeout_task , websocket , "websocket_close_timeout" );
294297
295298 aws_linked_list_init (& websocket -> thread_data .outgoing_frame_list );
296299
@@ -1118,13 +1121,49 @@ static int s_handler_shutdown(
11181121 AWS_LS_HTTP_WEBSOCKET ,
11191122 "id=%p: Outgoing CLOSE frame queued, handler will finish shutdown once it's sent." ,
11201123 (void * )websocket );
1124+ /* schedule a task to run after 1 sec. If the CLOSE still not sent at that time, we should just cancel
1125+ * sending it and shutdown the channel. */
1126+ uint64_t schedule_time = 0 ;
1127+ aws_channel_current_clock_time (websocket -> channel_slot -> channel , & schedule_time );
1128+ schedule_time += AWS_WEBSOCKET_CLOSE_TIMEOUT ;
1129+ AWS_LOGF_TRACE (
1130+ AWS_LS_HTTP_WEBSOCKET ,
1131+ "id=%p: websocket_close_timeout task will be run at timestamp %" PRIu64 ,
1132+ (void * )websocket ,
1133+ schedule_time );
1134+ aws_channel_schedule_task_future (
1135+ websocket -> channel_slot -> channel , & websocket -> close_timeout_task , schedule_time );
11211136 }
11221137 }
11231138 }
11241139
11251140 return AWS_OP_SUCCESS ;
11261141}
11271142
1143+ static void s_close_timeout_task (struct aws_channel_task * task , void * arg , enum aws_task_status status ) {
1144+ (void )task ;
1145+ if (status != AWS_TASK_STATUS_RUN_READY ) {
1146+ /* If channel has shut down, don't need to resume sending payload */
1147+ return ;
1148+ }
1149+
1150+ struct aws_websocket * websocket = arg ;
1151+ AWS_ASSERT (aws_channel_thread_is_callers_thread (websocket -> channel_slot -> channel ));
1152+
1153+ if (!websocket -> thread_data .is_shutting_down_and_waiting_for_close_frame_to_be_written ) {
1154+ /* Not waiting for write to complete, which means the CLOSE frame has sent, just do nothing */
1155+ return ;
1156+ }
1157+
1158+ AWS_LOGF_WARN (
1159+ AWS_LS_HTTP_WEBSOCKET ,
1160+ "id=%p: Failed to send CLOSE frame, timeout happened, shutdown the channel" ,
1161+ (void * )websocket );
1162+
1163+ s_stop_writing (websocket , AWS_ERROR_HTTP_CONNECTION_CLOSED );
1164+ s_finish_shutdown (websocket );
1165+ }
1166+
11281167static void s_finish_shutdown (struct aws_websocket * websocket ) {
11291168 AWS_ASSERT (aws_channel_thread_is_callers_thread (websocket -> channel_slot -> channel ));
11301169 AWS_ASSERT (websocket -> thread_data .is_writing_stopped );
0 commit comments