VPP-83 Allow non-privileged clients to use the vpp binary API.

Use the command line argument "api-segment { uid <nnn> gid <nnn> }" to
configure shared memory segment file ownership. Defaults to uid = gid
= 0.  Shared-memory segments are explicitly set to 0770 mode, aka
"rwxrwx---".

Change-Id: Ic5d596b68139add61e7de6ace035c57dfd030111
Signed-off-by: Dave Barach <dave@barachs.net>
diff --git a/vlib-api/vlibapi/api.h b/vlib-api/vlibapi/api.h
index fc2c30c..3c4b68d 100644
--- a/vlib-api/vlibapi/api.h
+++ b/vlib-api/vlibapi/api.h
@@ -134,6 +134,10 @@
     /* vector of message ranges */
     vl_api_msg_range_t *msg_ranges;
 
+    /* gid for the api shared memory region */
+    int api_gid;
+    int api_uid;
+
     /* Client-only data structures */
     unix_shared_memory_queue_t *vl_input_queue;
 
diff --git a/vlib-api/vlibapi/api_shared.c b/vlib-api/vlibapi/api_shared.c
index 308f002..0600e62 100644
--- a/vlib-api/vlibapi/api_shared.c
+++ b/vlib-api/vlibapi/api_shared.c
@@ -647,6 +647,14 @@
     once = 1;
 
     am->region_name = "/unset";
+    /* 
+     * Eventually passed to fchown, -1 => "current user" 
+     * instead of 0 => "root". A very fine disctinction at best.
+     */
+    if (am->api_uid == 0)
+        am->api_uid = -1;
+    if (am->api_gid == 0)
+        am->api_gid = -1;
 
     return (0);
 }
diff --git a/vlib-api/vlibmemory/api.h b/vlib-api/vlibmemory/api.h
index 516d321..1231944 100644
--- a/vlib-api/vlibmemory/api.h
+++ b/vlib-api/vlibmemory/api.h
@@ -133,6 +133,8 @@
 void vl_client_api_unmap (void);
 void vl_set_memory_region_name (char *name);
 void vl_set_memory_root_path (char *root_path);
+void vl_set_memory_uid (int uid);
+void vl_set_memory_gid (int gid);
 void vl_enable_disable_memory_api (vlib_main_t *vm, int yesno);
 void vl_client_disconnect_from_vlib (void);
 int vl_client_connect_to_vlib(char *svm_name, char *client_name, 
diff --git a/vlib-api/vlibmemory/memory_shared.c b/vlib-api/vlibmemory/memory_shared.c
index a321943..71150fd 100644
--- a/vlib-api/vlibmemory/memory_shared.c
+++ b/vlib-api/vlibmemory/memory_shared.c
@@ -197,9 +197,23 @@
     am->root_path = name;
 }
 
+void vl_set_memory_uid (int uid)
+{
+    api_main_t *am = &api_main;
+
+    am->api_uid = uid;
+}
+
+void vl_set_memory_gid (int gid)
+{
+    api_main_t *am = &api_main;
+
+    am->api_gid = gid;
+}
+
 int vl_map_shmem (char *region_name, int is_vlib)
 {
-    svm_map_region_args_t *a = 0;
+    svm_map_region_args_t _a, *a = &_a;
     svm_region_t *vlib_rp, *root_rp;
     void *oldheap;
     vl_shmem_hdr_t *shmem_hdr=0;
@@ -210,16 +224,16 @@
     if (is_vlib == 0)
         svm_region_init_chroot(am->root_path);
 
-    vec_validate (a, 0);
+    memset (a, 0, sizeof (*a));
 
     a->name = region_name;
     a->size = 16<<20;
     a->flags = SVM_FLAGS_MHEAP;
+    a->uid = am->api_uid;
+    a->gid = am->api_gid;
 
     vlib_rp = svm_region_find_or_create (a);
     
-    vec_free (a);
-
     if (vlib_rp == 0)
         return (-2);
 
@@ -273,25 +287,8 @@
             /* Clean up the root region client list */
             pthread_mutex_lock (&root_rp->mutex);
             svm_client_scan_this_region_nolock (root_rp);
-            pthread_mutex_unlock (&root_rp->mutex);
-        } else {
-            pthread_mutex_unlock (&vlib_rp->mutex);
-            /* 
-             * Make sure the vlib app is really there...
-             * Wait up to 100 seconds... 
-             */
-            for (i = 0; i < 10000; i++) {
-                /* Yup, it's there, off we go... */
-                if (kill (am->shmem_hdr->vl_pid, 0) >= 0)
-                    break;
-
-                ts.tv_sec = 0;
-                ts.tv_nsec = 10000*1000;  /* 10 ms */
-                while (nanosleep(&ts, &tsrem) < 0)
-                    ts = tsrem;
-            }
-        }
-
+        } 
+        pthread_mutex_unlock (&vlib_rp->mutex);
         am->vlib_rp = vlib_rp;
         vec_add1(am->mapped_shmem_regions, vlib_rp);
         return 0;
diff --git a/vlib-api/vlibmemory/memory_vlib.c b/vlib-api/vlibmemory/memory_vlib.c
index 0cac49d..0fef64c 100644
--- a/vlib-api/vlibmemory/memory_vlib.c
+++ b/vlib-api/vlibmemory/memory_vlib.c
@@ -343,7 +343,6 @@
 
 static u64 vector_rate_histogram[SLEEP_N_BUCKETS];
 
-static void memclnt_queue_signal (int signum);
 static void memclnt_queue_callback (vlib_main_t *vm);
 
 static uword
@@ -362,8 +361,6 @@
     f64 vector_rate;
     
     vlib_set_queue_signal_callback (vm, memclnt_queue_callback);
-    am->vlib_signal = SIGUSR1;
-    signal (am->vlib_signal, memclnt_queue_signal);
     
     if ((rv = memory_api_init(am->region_name)) < 0) {
         clib_warning("memory_api_init returned %d, wait for godot...", rv);
@@ -458,6 +455,7 @@
         }
 
 	event_type = vlib_process_wait_for_event_or_clock (vm, sleep_time);
+        vm->queue_signal_pending = 0;
         vlib_process_get_events (vm, 0 /* event_data */);
 
         if (vlib_time_now (vm) > dead_client_scan_time) {
@@ -621,27 +619,33 @@
     .state = VLIB_NODE_STATE_DISABLED,
 };
 
-static void
-memclnt_queue_signal (int signum)
-{
-    vlib_main_t * vm = vlib_get_main();
-
-    vm->queue_signal_pending = 1;
-    vm->api_queue_nonempty = 1;
-}
-
 static void 
 memclnt_queue_callback (vlib_main_t *vm)
 {
-#if 0
-    /* If we need to manually suspend / resume the memclnt process */
-    vlib_node_t * n = vlib_get_node (vm, memclnt_node.index);
-    vlib_process_t * p = vlib_get_process_from_node (vm, n);
-#endif
+  static volatile int * cursizep;
 
-    vm->queue_signal_pending = 0;
-    vlib_process_signal_event 
-        (vm, memclnt_node.index, /* event_type */ 0, /* event_data */ 0);
+  if (PREDICT_FALSE (cursizep == 0))
+    {
+      api_main_t *am = &api_main;
+      vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
+      unix_shared_memory_queue_t * q;            
+      
+      if (shmem_hdr == 0)
+        return;
+      
+      q = shmem_hdr->vl_input_queue;
+      if (q == 0)
+        return;
+      cursizep = &q->cursize;
+    }
+  
+  if (*cursizep >= 1)
+    {
+      vm->queue_signal_pending = 1;
+      vm->api_queue_nonempty = 1;
+      vlib_process_signal_event (vm, memclnt_node.index, 
+                                 /* event_type */ 0, /* event_data */ 0);
+    }
 }
 
 void vl_enable_disable_memory_api (vlib_main_t *vm, int enable)
@@ -1049,8 +1053,8 @@
 vlibmemory_init (vlib_main_t * vm)
 {
   api_main_t *am = &api_main;
-  /* Normally NULL, can be set by cmd line "chroot {prefix foo}" */
-  svm_region_init_chroot (am->root_path);
+  /* Normally NULL / 0, set by cmd line "api-segment" */
+  svm_region_init_chroot_uid_gid (am->root_path, am->api_uid, am->api_gid);
   return 0;
 }