tcp: improve waitclose in closing states
[vpp.git] / src / vnet / session / session.c
index b48459d..6492ce7 100644 (file)
@@ -66,6 +66,7 @@ session_send_evt_to_thread (void *data, void *args, u32 thread_index,
       evt->rpc_args.arg = args;
       break;
     case FIFO_EVENT_APP_TX:
+    case SESSION_IO_EVT_TX_FLUSH:
     case FIFO_EVENT_BUILTIN_RX:
       evt->fifo = data;
       break;
@@ -819,6 +820,7 @@ stream_session_delete_notify (transport_connection_t * tc)
       break;
     case SESSION_STATE_CLOSED:
     case SESSION_STATE_ACCEPTING:
+    case SESSION_STATE_CLOSED_WAITING:
       stream_session_delete (s);
       break;
     default:
@@ -827,6 +829,24 @@ stream_session_delete_notify (transport_connection_t * tc)
     }
 }
 
+/**
+ * Notification from transport that session can be closed
+ *
+ * Should be called by transport only if it was closed with non-empty
+ * tx fifo and once it decides to begin the closing procedure prior to
+ * issuing a delete notify. This gives the chance to the session layer
+ * to cleanup any outstanding events.
+ */
+void
+session_stream_close_notify (transport_connection_t * tc)
+{
+  stream_session_t *s;
+
+  if (!(s = session_get_if_valid (tc->s_index, tc->thread_index)))
+    return;
+  s->session_state = SESSION_STATE_CLOSED;
+}
+
 /**
  * Notify application that connection has been reset.
  */
@@ -1112,7 +1132,18 @@ stream_session_disconnect_transport (stream_session_t * s)
       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);
 }