diff options
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/dev.c | 125 | 
1 files changed, 99 insertions, 26 deletions
| diff --git a/src/lib/dev.c b/src/lib/dev.c index 4416a03e..0acc7455 100644 --- a/src/lib/dev.c +++ b/src/lib/dev.c @@ -33,6 +33,7 @@  #include <ouroboros/errno.h>  #include <ouroboros/dev.h>  #include <ouroboros/ipcp-dev.h> +#include <ouroboros/list.h>  #include <ouroboros/local-dev.h>  #include <ouroboros/sockets.h>  #include <ouroboros/fccntl.h> @@ -68,16 +69,6 @@  #define SYMMKEYSZ 32  #define MSGBUFSZ  2048 -struct flow_set { -        size_t idx; -}; - -struct fqueue { -        int    fqueue[2 * SHM_BUFFER_SIZE]; /* Safe copy from shm. */ -        size_t fqsize; -        size_t next; -}; -  enum port_state {          PORT_NULL = 0,          PORT_INIT, @@ -119,6 +110,25 @@ struct flow {          struct frcti *        frcti;  }; +struct flow_set_entry { +        struct list_head next; + +        int fd; +}; + +struct flow_set { +        size_t idx; + +        struct list_head flows; +        pthread_rwlock_t lock; +}; + +struct fqueue { +        int    fqueue[2 * SHM_BUFFER_SIZE]; /* Safe copy from shm. */ +        size_t fqsize; +        size_t next; +}; +  struct {          char *                prog;          pid_t                 pid; @@ -1254,24 +1264,36 @@ ssize_t flow_read(int    fd,  struct flow_set * fset_create()  { -        struct flow_set * set = malloc(sizeof(*set)); +        struct flow_set * set; + +        set = malloc(sizeof(*set));          if (set == NULL) -                return NULL; +                goto fail_malloc; + +        if (pthread_rwlock_init(&set->lock, NULL)) +                goto fail_lock_init;          assert(ai.fqueues);          pthread_rwlock_wrlock(&ai.lock);          set->idx = bmp_allocate(ai.fqueues); -        if (!bmp_is_id_valid(ai.fqueues, set->idx)) { -                pthread_rwlock_unlock(&ai.lock); -                free(set); -                return NULL; -        } +        if (!bmp_is_id_valid(ai.fqueues, set->idx)) +                goto fail_bmp_alloc;          pthread_rwlock_unlock(&ai.lock); +        list_head_init(&set->flows); +          return set; + + fail_bmp_alloc: +        pthread_rwlock_unlock(&ai.lock); +        pthread_rwlock_destroy(&set->lock); + fail_lock_init: +        free(set); + fail_malloc: +        return NULL;  }  void fset_destroy(struct flow_set * set) @@ -1287,6 +1309,8 @@ void fset_destroy(struct flow_set * set)          pthread_rwlock_unlock(&ai.lock); +        pthread_rwlock_destroy(&set->lock); +          free(set);  } @@ -1310,30 +1334,57 @@ void fqueue_destroy(struct fqueue * fq)  void fset_zero(struct flow_set * set)  { +        struct list_head * p; +        struct list_head * h; +          if (set == NULL)                  return; +        pthread_rwlock_wrlock(&set->lock); + +        list_for_each_safe(p, h, &set->flows) { +                struct flow_set_entry * e; +                e = list_entry(p, struct flow_set_entry, next); +                list_del(&e->next); +                free(e); +        } + +        pthread_rwlock_unlock(&set->lock); +          shm_flow_set_zero(ai.fqset, set->idx);  }  int fset_add(struct flow_set * set,               int               fd)  { -        int    ret; -        size_t packets; -        size_t i; +        struct flow_set_entry * fse; +        int                     ret; +        size_t                  packets; +        size_t                  i; -        if (set == NULL || fd < 0 || fd > SYS_MAX_FLOWS) +        if (set == NULL || fd < 0 || fd >= SYS_MAX_FLOWS)                  return -EINVAL; +        fse = malloc(sizeof(*fse)); +        if (fse == NULL) +                return -ENOMEM; +          pthread_rwlock_wrlock(&ai.lock);          if (ai.flows[fd].flow_id < 0) { -                pthread_rwlock_unlock(&ai.lock); -                return -EINVAL; +                ret = -EINVAL; +                goto fail;          }          ret = shm_flow_set_add(ai.fqset, set->idx, ai.flows[fd].flow_id); +        if (ret < 0) +                goto fail; + +        pthread_rwlock_wrlock(&set->lock); + +        list_add_tail(&fse->next, &set->flows); + +        pthread_rwlock_unlock(&set->lock);          packets = shm_rbuff_queued(ai.flows[fd].rx_rb);          for (i = 0; i < packets; i++) @@ -1342,12 +1393,20 @@ int fset_add(struct flow_set * set,          pthread_rwlock_unlock(&ai.lock);          return ret; + + fail: +        pthread_rwlock_unlock(&ai.lock); +        free(fse); +        return ret;  }  void fset_del(struct flow_set * set,                int               fd)  { -        if (set == NULL || fd < 0 || fd > SYS_MAX_FLOWS) +        struct list_head * p; +        struct list_head * h; + +        if (set == NULL || fd < 0 || fd >= SYS_MAX_FLOWS)                  return;          pthread_rwlock_rdlock(&ai.lock); @@ -1355,15 +1414,29 @@ void fset_del(struct flow_set * set,          if (ai.flows[fd].flow_id >= 0)                  shm_flow_set_del(ai.fqset, set->idx, ai.flows[fd].flow_id); +        pthread_rwlock_wrlock(&set->lock); + +        list_for_each_safe(p, h, &set->flows) { +                struct flow_set_entry * e; +                e = list_entry(p, struct flow_set_entry, next); +                if (e->fd == fd) { +                        list_del(&e->next); +                        free(e); +                        break; +                } +        } + +        pthread_rwlock_unlock(&set->lock); +          pthread_rwlock_unlock(&ai.lock);  }  bool fset_has(const struct flow_set * set,                int                     fd)  { -        bool ret = false; +        bool ret; -        if (set == NULL || fd < 0 || fd > SYS_MAX_FLOWS) +        if (set == NULL || fd < 0 || fd >= SYS_MAX_FLOWS)                  return false;          pthread_rwlock_rdlock(&ai.lock); | 
