summaryrefslogtreecommitdiff
path: root/src/rpc/skabus_rpcd_interface.c
blob: 600b91a2eba0d7d6810ce705435acf7464c2a40f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/* ISC license. */

#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <regex.h>

#include <skalibs/posixplz.h>
#include <skalibs/strerr.h>
#include <skalibs/genalloc.h>
#include <skalibs/gensetdyn.h>
#include <skalibs/avltree.h>
#include <skabus/rpc.h>
#include "skabus-rpcd.h"

static inline void interface_free (interface_t *p)
{
  p->name[0] = p->name[1] = 0 ;
  gensetdyn_free(&p->queries) ;
}

static void *if_dtok (uint32_t d, void *x)
{
  (void)x ;
  return INTERFACE(d)->name ;
}

static int if_cmp (void const *a, void const *b, void *x)
{
  (void)x ;
  return strncmp((char const *)a, (char const *)b, SKABUS_RPC_INTERFACE_MAXLEN) ;
}

gensetdyn interfaces = GENSETDYN_ZERO ;
static avltree ifdict = AVLTREE_INIT(2, 3, 8, &if_dtok, &if_cmp, 0) ;

static inline void interface_delete (uint32_t i)
{
  interface_t *y = INTERFACE(i) ;
  if (!avltree_delete(&ifdict, y->name))
    strerr_diefu1sys(111, "avltree_delete in interface_delete") ;
  interface_free(y) ;
  if (!gensetdyn_delete(&interfaces, i))
    strerr_diefu1sys(111, "gensetdyn_delete in interface_delete") ;
}

static int query_fail_iter (char *s, void *reason)
{
  uint32_t i = *(uint32_t *)s ;
  query_fail(i, *(unsigned char *)reason) ;
  return 1 ;
}

static inline void client_interfacemove (client_t *c, uint32_t from, uint32_t to)
{
  uint32_t *ifaces = genalloc_s(uint32_t, &c->interfaces) ;
  INTERFACE(ifaces[from])->index = to ;
  ifaces[to] = ifaces[from] ;
}

void interface_remove (uint32_t i)
 {
  interface_t *y = INTERFACE(i) ;
  client_t *c = CLIENT(y->client) ;
  uint32_t n = gensetdyn_n(&y->queries) ;
  unsigned char reason = ECONNRESET ;
  gensetdyn_iter(&y->queries, &query_fail_iter, &reason) ;
  n = genalloc_len(uint32_t, &c->interfaces) ;
  client_interfacemove(c, n-1, y->index) ;
  genalloc_setlen(uint32_t, &c->interfaces, n-1) ;
  interface_delete(i) ;
}

int interface_lookup_by_name (char const *s, uint32_t *d)
{
  return avltree_search(&ifdict, s, d) ;
}

int interface_add (uint32_t *d, char const *name, size_t namelen, uint32_t client, char const *re, uint32_t id)
{
  uint32_t yy ;
  int e ;
  genalloc *g = &CLIENT(client)->interfaces ;
  if (!genalloc_readyplus(uint32_t, g, 1)) return 0 ;
  if (!gensetdyn_new(&interfaces, &yy)) return 0 ;
  {
    interface_t *y = INTERFACE(yy) ;
    int r = skalibs_regcomp(&y->re, re, REG_EXTENDED | REG_NOSUB) ;
    if (r)
    {
      e = r == REG_ESPACE ? ENOMEM : EINVAL ;
      goto err ;
    }
    memcpy(y->name, name, namelen) ; y->name[namelen] = 0 ;
    y->id = id ;
    y->client = client ;
    y->index = genalloc_len(uint32_t, g) - 1 ;
    y->queries = gensetdyn_zero ;
    if (!avltree_insert(&ifdict, yy))
    {
      e = errno ;
      regfree(&y->re) ;
      goto err ;
    }
  }
  genalloc_append(uint32_t, g, &yy) ;
  *d = yy ;
  return 1 ;

 err:
  if (!gensetdyn_delete(&interfaces, yy))
    strerr_diefu1sys(111, "gensetdyn_delete in interface_add") ;
  errno = e ;
  return 0 ;
}