From e14d0da88d4f3fcd0c19c231b59d31189c4d71ad Mon Sep 17 00:00:00 2001
From: dimitri staessens <dimitri.staessens@intec.ugent.be>
Date: Fri, 15 Jul 2016 15:49:23 +0200
Subject: irmd: Fix accessing reg_api struct after destroy

The destroy now only frees after all threads stopped using the object.
Also fixes a SEGV when trying to allocate a flow to a remote name.
---
 src/irmd/main.c     | 30 ++++++++++++++++++++++++++++++
 src/irmd/registry.c | 49 ++++++++++++++-----------------------------------
 src/irmd/registry.h |  2 +-
 3 files changed, 45 insertions(+), 36 deletions(-)

(limited to 'src/irmd')

diff --git a/src/irmd/main.c b/src/irmd/main.c
index 1da4b310..625c28c8 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -247,6 +247,36 @@ static pid_t get_ipcp_by_dst_name(char * dst_name)
         struct list_head * pos = NULL;
         char * dif_name =
                 registry_get_dif_for_dst(&instance->registry, dst_name);
+        if (dif_name == NULL) {
+                list_for_each(pos, &instance->ipcps) {
+                        struct ipcp_entry * e =
+                                list_entry(pos, struct ipcp_entry, next);
+                        if (e->type == IPCP_NORMAL) {
+                                dif_name = e->dif_name;
+                                break;
+                        }
+                }
+
+                list_for_each(pos, &instance->ipcps) {
+                        struct ipcp_entry * e =
+                                list_entry(pos, struct ipcp_entry, next);
+                        if (e->type == IPCP_SHIM_ETH_LLC) {
+                                dif_name = e->dif_name;
+                                break;
+                        }
+                }
+
+
+                list_for_each(pos, &instance->ipcps) {
+                        struct ipcp_entry * e =
+                                list_entry(pos, struct ipcp_entry, next);
+                        if (e->type == IPCP_SHIM_UDP) {
+                                dif_name = e->dif_name;
+                                break;
+                        }
+                }
+        }
+
         if (dif_name == NULL)
                 return -1;
 
diff --git a/src/irmd/registry.c b/src/irmd/registry.c
index f688e1cc..32741460 100644
--- a/src/irmd/registry.c
+++ b/src/irmd/registry.c
@@ -63,7 +63,7 @@ struct reg_api * reg_api_create(pid_t api)
         i->state = REG_I_WAKE;
 
         pthread_mutex_init(&i->mutex, NULL);
-        pthread_cond_init(&i->wakeup, NULL);
+        pthread_cond_init(&i->cond_state, NULL);
 
         INIT_LIST_HEAD(&i->next);
 
@@ -72,21 +72,18 @@ struct reg_api * reg_api_create(pid_t api)
 
 void reg_api_destroy(struct reg_api * i)
 {
-        bool wait = true;
         pthread_mutex_lock(&i->mutex);
-        i->state = REG_I_NULL;
 
-        pthread_cond_broadcast(&i->wakeup);
+        if (i->state != REG_I_SLEEP)
+                i->state = REG_I_WAKE;
+        else
+                i->state = REG_I_NULL;
+
+        pthread_cond_broadcast(&i->cond_state);
         pthread_mutex_unlock(&i->mutex);
 
-        while (wait) {
-                pthread_mutex_lock(&i->mutex);
-                if (pthread_cond_destroy(&i->wakeup))
-                        pthread_cond_broadcast(&i->wakeup);
-                else
-                        wait = false;
-                pthread_mutex_unlock(&i->mutex);
-        }
+        while (i->state != REG_I_WAKE)
+                ;
 
         pthread_mutex_destroy(&i->mutex);
 
@@ -107,7 +104,10 @@ void reg_api_sleep(struct reg_api * i)
                              (void *) &i->mutex);
 
         while (i->state == REG_I_SLEEP)
-                pthread_cond_wait(&i->wakeup, &i->mutex);
+                pthread_cond_wait(&i->cond_state, &i->mutex);
+
+        i->state = REG_I_WAKE;
+        pthread_cond_signal(&i->cond_state);
 
         pthread_cleanup_pop(true);
 }
@@ -123,7 +123,7 @@ void reg_api_wake(struct reg_api * i)
 
         i->state = REG_I_WAKE;
 
-        pthread_cond_signal(&i->wakeup);
+        pthread_cond_signal(&i->cond_state);
         pthread_mutex_unlock(&i->mutex);
 }
 
@@ -674,27 +674,6 @@ char * registry_get_dif_for_dst(struct list_head * registry,
                 return NULL;
         } else {
                 LOG_DBGF("No local ap %s found.", dst_name);
-                list_for_each(pos, &re->difs) {
-                        struct reg_dif * rd =
-                                list_entry(pos, struct reg_dif, next);
-                        if (rd->type == IPCP_NORMAL)
-                                return rd->dif_name;
-                }
-
-                list_for_each(pos, &re->difs) {
-                        struct reg_dif * rd =
-                                list_entry(pos, struct reg_dif, next);
-                        if (rd->type == IPCP_SHIM_ETH_LLC)
-                                return rd->dif_name;
-                }
-
-                list_for_each(pos, &re->difs) {
-                        struct reg_dif * rd =
-                                list_entry(pos, struct reg_dif, next);
-                        if (rd->type == IPCP_SHIM_UDP)
-                                return rd->dif_name;
-                }
-
                 return NULL;
         }
 }
diff --git a/src/irmd/registry.h b/src/irmd/registry.h
index 04ce7cf8..8e9a7af1 100644
--- a/src/irmd/registry.h
+++ b/src/irmd/registry.h
@@ -59,7 +59,7 @@ struct reg_api {
 
         /* the api will block on this */
         enum reg_i_state state;
-        pthread_cond_t   wakeup;
+        pthread_cond_t   cond_state;
         pthread_mutex_t  mutex;
 };
 
-- 
cgit v1.2.3