break;
case SESSION_STATE_CLOSED:
case SESSION_STATE_ACCEPTING:
+ case SESSION_STATE_CLOSED_WAITING:
stream_session_delete (s);
break;
default:
session_free_w_fifos (s);
return;
}
- s->session_state = SESSION_STATE_CLOSED;
+
+ /* If tx queue wasn't drained, change state to closed waiting for transport.
+ * This way, the transport, if it so wishes, can continue to try sending the
+ * outstanding data (in closed state it cannot). It MUST however at one
+ * point, either after sending everything or after a timeout, call delete
+ * notify. This will finally lead to the complete cleanup of the session.
+ */
+ if (svm_fifo_max_dequeue (s->server_tx_fifo))
+ s->session_state = SESSION_STATE_CLOSED_WAITING;
+ else
+ s->session_state = SESSION_STATE_CLOSED;
+
tp_vfts[session_get_transport_proto (s)].close (s->connection_index,
s->thread_index);
}
SESSION_STATE_OPENED,
SESSION_STATE_TRANSPORT_CLOSING,
SESSION_STATE_CLOSING,
+ SESSION_STATE_CLOSED_WAITING,
SESSION_STATE_CLOSED,
SESSION_STATE_N_STATES,
} stream_session_state_t;
else if (tc->state == TCP_STATE_FIN_WAIT_1)
{
tcp_connection_timers_reset (tc);
+ /* If FIN pending send it before closing */
+ if (tc->flags & TCP_CONN_FINPNDG)
+ tcp_send_fin (tc);
tc->state = TCP_STATE_CLOSED;
/* Wait for session layer to clean up tx events */
tcp_timer_set (tc, TCP_TIMER_WAITCLOSE, TCP_CLEANUP_TIME);
{
u32 thread_index = vm->thread_index, errors = 0, *first_buffer;
tcp_worker_ctx_t *wrk = tcp_get_worker (thread_index);
- u32 n_left_from, *from;
+ u32 n_left_from, *from, max_dequeue;
from = first_buffer = vlib_frame_vector_args (from_frame);
n_left_from = from_frame->n_vectors;
if (tc0->flags & TCP_CONN_FINPNDG)
{
/* TX fifo finally drained */
- if (!session_tx_fifo_max_dequeue (&tc0->connection))
+ max_dequeue = session_tx_fifo_max_dequeue (&tc0->connection);
+ if (max_dequeue <= tc0->burst_acked)
tcp_send_fin (tc0);
}
/* If FIN is ACKed */