session: fix local session disconnects
[vpp.git] / src / vnet / session / application.c
index 9020d1c..7bc2c11 100644 (file)
@@ -28,6 +28,11 @@ static application_t *app_pool;
  */
 static uword *app_by_api_client_index;
 
+/**
+ * Hash table of builtin apps by name
+ */
+static uword *app_by_name;
+
 static u8 *
 app_get_name_from_reg_index (application_t * app)
 {
@@ -43,6 +48,14 @@ app_get_name_from_reg_index (application_t * app)
   return app_name;
 }
 
+static u8 *
+app_get_name (application_t * app)
+{
+  if (!app->name)
+    return app_get_name_from_reg_index (app);
+  return app->name;
+}
+
 u32
 application_session_table (application_t * app, u8 fib_proto)
 {
@@ -104,13 +117,19 @@ application_name_from_index (u32 app_index)
 static void
 application_table_add (application_t * app)
 {
-  hash_set (app_by_api_client_index, app->api_client_index, app->index);
+  if (app->api_client_index != APP_INVALID_INDEX)
+    hash_set (app_by_api_client_index, app->api_client_index, app->index);
+  else if (app->name)
+    hash_set_mem (app_by_name, app->name, app->index);
 }
 
 static void
 application_table_del (application_t * app)
 {
-  hash_unset (app_by_api_client_index, app->api_client_index);
+  if (app->api_client_index != APP_INVALID_INDEX)
+    hash_unset (app_by_api_client_index, app->api_client_index);
+  else if (app->name)
+    hash_unset_mem (app_by_name, app->name);
 }
 
 application_t *
@@ -124,6 +143,17 @@ application_lookup (u32 api_client_index)
   return 0;
 }
 
+application_t *
+application_lookup_name (const u8 * name)
+{
+  uword *p;
+  p = hash_get_mem (app_by_name, name);
+  if (p)
+    return application_get (p[0]);
+
+  return 0;
+}
+
 application_t *
 application_new ()
 {
@@ -209,7 +239,11 @@ application_del (application_t * app)
    */
   application_local_sessions_del (app);
 
+  vec_free (app->tls_cert);
+  vec_free (app->tls_key);
+
   application_table_del (app);
+  vec_free (app->name);
   pool_put (app_pool, app);
 }
 
@@ -254,8 +288,8 @@ application_verify_cfg (ssvm_segment_type_t st)
 }
 
 int
-application_init (application_t * app, u32 api_client_index, u64 * options,
-                 session_cb_vft_t * cb_fns)
+application_init (application_t * app, u32 api_client_index, u8 * app_name,
+                 u64 * options, session_cb_vft_t * cb_fns)
 {
   ssvm_segment_type_t seg_type = SSVM_SEGMENT_MEMFD;
   u32 first_seg_size, prealloc_fifo_pairs;
@@ -302,6 +336,8 @@ application_init (application_t * app, u32 api_client_index, u64 * options,
     props->tx_fifo_size = options[APP_OPTIONS_TX_FIFO_SIZE];
   if (options[APP_OPTIONS_EVT_QUEUE_SIZE])
     props->evt_q_size = options[APP_OPTIONS_EVT_QUEUE_SIZE];
+  if (options[APP_OPTIONS_TLS_ENGINE])
+    app->tls_engine = options[APP_OPTIONS_TLS_ENGINE];
   props->segment_type = seg_type;
 
   first_seg_size = options[APP_OPTIONS_SEGMENT_SIZE];
@@ -323,6 +359,7 @@ application_init (application_t * app, u32 api_client_index, u64 * options,
   app->local_connects = hash_create (0, sizeof (u64));
   app->proxied_transports = options[APP_OPTIONS_PROXY_TRANSPORT];
   app->event_queue = segment_manager_event_queue (sm);
+  app->name = vec_dup (app_name);
 
   /* If no scope enabled, default to global */
   if (!application_has_global_scope (app)
@@ -473,10 +510,22 @@ int
 application_open_session (application_t * app, session_endpoint_t * sep,
                          u32 api_context)
 {
-  segment_manager_t *sm;
   int rv;
 
   /* Make sure we have a segment manager for connects */
+  application_alloc_connects_segment_manager (app);
+
+  if ((rv = session_open (app->index, sep, api_context)))
+    return rv;
+
+  return 0;
+}
+
+int
+application_alloc_connects_segment_manager (application_t * app)
+{
+  segment_manager_t *sm;
+
   if (app->connects_seg_manager == APP_INVALID_SEGMENT_MANAGER_INDEX)
     {
       sm = application_alloc_segment_manager (app);
@@ -484,10 +533,6 @@ application_open_session (application_t * app, session_endpoint_t * sep,
        return -1;
       app->connects_seg_manager = segment_manager_index (sm);
     }
-
-  if ((rv = session_open (app->index, sep, api_context)))
-    return rv;
-
   return 0;
 }
 
@@ -831,6 +876,7 @@ application_start_local_listen (application_t * server,
   /* Store the original session type for the unbind */
   ll->listener_session_type =
     session_type_from_proto_and_ip (sep->transport_proto, sep->is_ip4);
+  ll->transport_listener_index = ~0;
 
   *handle = application_local_session_handle (ll);
   session_lookup_add_session_endpoint (table_index, sep, *handle);
@@ -1033,37 +1079,53 @@ application_local_session_connect_notify (local_session_t * ls)
 }
 
 int
-application_local_session_disconnect (u32 app_index, local_session_t * ls)
+application_local_session_cleanup (application_t * client,
+                                  application_t * server,
+                                  local_session_t * ls)
 {
   svm_fifo_segment_private_t *seg;
-  application_t *client, *server;
   segment_manager_t *sm;
   uword client_key;
+  u8 has_transport;
 
-  client = application_get_if_valid (ls->client_index);
-  server = application_get (ls->app_index);
-
-  if (ls->session_state == SESSION_STATE_CLOSED)
-    {
-    cleanup:
-      client_key = application_client_local_connect_key (ls);
-      sm = application_get_local_segment_manager_w_session (server, ls);
-      seg = segment_manager_get_segment (sm, ls->svm_segment_index);
+  has_transport = session_has_transport ((stream_session_t *) ls);
+  client_key = application_client_local_connect_key (ls);
+  if (!has_transport)
+    sm = application_get_local_segment_manager_w_session (server, ls);
+  else
+    sm = application_get_listen_segment_manager (server,
+                                                (stream_session_t *) ls);
 
-      if (client)
-       {
-         hash_unset (client->local_connects, client_key);
-         client->cb_fns.del_segment_callback (client->api_client_index,
-                                              &seg->ssvm);
-       }
+  seg = segment_manager_get_segment (sm, ls->svm_segment_index);
+  if (client)
+    hash_unset (client->local_connects, client_key);
 
+  if (!has_transport)
+    {
       server->cb_fns.del_segment_callback (server->api_client_index,
                                           &seg->ssvm);
+      if (client)
+       client->cb_fns.del_segment_callback (client->api_client_index,
+                                            &seg->ssvm);
       segment_manager_del_segment (sm, seg);
-      application_free_local_session (server, ls);
-      return 0;
     }
 
+  application_free_local_session (server, ls);
+
+  return 0;
+}
+
+int
+application_local_session_disconnect (u32 app_index, local_session_t * ls)
+{
+  application_t *client, *server;
+
+  client = application_get_if_valid (ls->client_index);
+  server = application_get (ls->app_index);
+
+  if (ls->session_state == SESSION_STATE_CLOSED)
+    return application_local_session_cleanup (client, server, ls);
+
   if (app_index == ls->client_index)
     {
       send_local_session_disconnect_callback (ls->app_index, ls);
@@ -1072,7 +1134,7 @@ application_local_session_disconnect (u32 app_index, local_session_t * ls)
     {
       if (!client)
        {
-         goto cleanup;
+         return application_local_session_cleanup (client, server, ls);
        }
       else if (ls->session_state < SESSION_STATE_READY)
        {
@@ -1081,11 +1143,11 @@ application_local_session_disconnect (u32 app_index, local_session_t * ls)
                                                     (stream_session_t *) ls,
                                                     1 /* is_fail */ );
          ls->session_state = SESSION_STATE_CLOSED;
-         goto cleanup;
+         return application_local_session_cleanup (client, server, ls);
        }
       else
        {
-         send_local_session_disconnect_callback (ls->client_index, ls);
+         send_local_session_disconnect_callback (client->index, ls);
        }
     }
 
@@ -1094,6 +1156,16 @@ application_local_session_disconnect (u32 app_index, local_session_t * ls)
   return 0;
 }
 
+int
+application_local_session_disconnect_w_index (u32 app_index, u32 ls_index)
+{
+  application_t *app;
+  local_session_t *ls;
+  app = application_get (app_index);
+  ls = application_get_local_session (app, ls_index);
+  return application_local_session_disconnect (app_index, ls);
+}
+
 void
 application_local_sessions_del (application_t * app)
 {
@@ -1155,6 +1227,30 @@ application_local_sessions_del (application_t * app)
   segment_manager_del (sm);
 }
 
+clib_error_t *
+vnet_app_add_tls_cert (vnet_app_add_tls_cert_args_t * a)
+{
+  application_t *app;
+  app = application_get (a->app_index);
+  if (!app)
+    return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
+                                  0, "app %u doesn't exist", a->app_index);
+  app->tls_cert = vec_dup (a->cert);
+  return 0;
+}
+
+clib_error_t *
+vnet_app_add_tls_key (vnet_app_add_tls_key_args_t * a)
+{
+  application_t *app;
+  app = application_get (a->app_index);
+  if (!app)
+    return clib_error_return_code (0, VNET_API_ERROR_APPLICATION_NOT_ATTACHED,
+                                  0, "app %u doesn't exist", a->app_index);
+  app->tls_key = vec_dup (a->key);
+  return 0;
+}
+
 u8 *
 format_application_listener (u8 * s, va_list * args)
 {
@@ -1342,21 +1438,19 @@ format_application (u8 * s, va_list * args)
                    "API Client", "Namespace", "Add seg size", "Rx fifo size",
                    "Tx fifo size");
       else
-       s =
-         format (s, "%-10s%-20s%-15s%-40s", "Index", "Name", "API Client",
-                 "Namespace");
+       s = format (s, "%-10s%-20s%-15s%-40s", "Index", "Name", "API Client",
+                   "Namespace");
       return s;
     }
 
-  app_name = app_get_name_from_reg_index (app);
+  app_name = app_get_name (app);
   app_ns_name = app_namespace_id_from_index (app->ns_index);
   props = application_segment_manager_properties (app);
   if (verbose)
-    s =
-      format (s, "%-10d%-20s%-15d%-15d%-15d%-15d%-15d", app->index, app_name,
-             app->api_client_index, app->ns_index,
-             props->add_segment_size,
-             props->rx_fifo_size, props->tx_fifo_size);
+    s = format (s, "%-10d%-20s%-15d%-15d%-15d%-15d%-15d", app->index,
+               app_name, app->api_client_index, app->ns_index,
+               props->add_segment_size, props->rx_fifo_size,
+               props->tx_fifo_size);
   else
     s = format (s, "%-10d%-20s%-15d%-40s", app->index, app_name,
                app->api_client_index, app_ns_name);