initial commit
[project/unetd.git] / service.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
4 */
5 #include <libubox/avl-cmp.h>
6 #include "unetd.h"
7
8 enum {
9 SERVICE_ATTR_TYPE,
10 SERVICE_ATTR_MEMBERS,
11 __SERVICE_ATTR_MAX
12 };
13
14 static const struct blobmsg_policy service_policy[__SERVICE_ATTR_MAX] = {
15 [SERVICE_ATTR_TYPE] = { "type", BLOBMSG_TYPE_STRING },
16 [SERVICE_ATTR_MEMBERS] = { "members", BLOBMSG_TYPE_ARRAY },
17 };
18
19 void network_services_init(struct network *net)
20 {
21 avl_init(&net->services, avl_strcmp, false, NULL);
22 }
23
24 void network_services_free(struct network *net)
25 {
26 struct network_service *s, *tmp;
27
28 avl_remove_all_elements(&net->services, s, node, tmp)
29 free(s);
30 }
31
32 static int
33 __service_parse_members(struct network *net, struct network_service *s,
34 const char *name)
35 {
36 struct network_group *group;
37 struct network_host *host;
38
39 if (name[0] != '@') {
40 host = avl_find_element(&net->hosts, name, host, node);
41
42 if (!host)
43 return 0;
44
45 if (s)
46 s->members[s->n_members++] = host;
47
48 return 1;
49 }
50
51 name++;
52 group = avl_find_element(&net->groups, name, group, node);
53 if (!group)
54 return 0;
55
56 if (s) {
57 memcpy(&s->members[s->n_members], group->members,
58 group->n_members * sizeof(group->members[0]));
59 s->n_members += group->n_members;
60 }
61
62 return group->n_members;
63 }
64
65 static int
66 service_parse_members(struct network *net, struct network_service *s,
67 struct blob_attr *data)
68 {
69 struct blob_attr *cur;
70 int rem;
71 int n = 0;
72
73 blobmsg_for_each_attr(cur, data, rem)
74 n += __service_parse_members(net, s, blobmsg_get_string(cur));
75
76 return n;
77 }
78
79 static void
80 service_add(struct network *net, struct blob_attr *data)
81 {
82 struct network_service *s;
83 struct blob_attr *tb[__SERVICE_ATTR_MAX];
84 struct blob_attr *cur;
85 const char *name = blobmsg_name(data);
86 const char *type = NULL;
87 char *name_buf, *type_buf;
88 int n_members;
89
90 blobmsg_parse(service_policy, __SERVICE_ATTR_MAX, tb,
91 blobmsg_data(data), blobmsg_len(data));
92
93 if ((cur = tb[SERVICE_ATTR_TYPE]) != NULL)
94 type = blobmsg_get_string(cur);
95
96 if (blobmsg_check_array(tb[SERVICE_ATTR_MEMBERS], BLOBMSG_TYPE_STRING) < 0)
97 return;
98
99 n_members = service_parse_members(net, NULL, tb[SERVICE_ATTR_MEMBERS]);
100 s = calloc_a(sizeof(*s) + n_members * sizeof(s->members[0]),
101 &name_buf, strlen(name) + 1,
102 &type_buf, type ? strlen(type) + 1 : 0);
103
104 s->node.key = strcpy(name_buf, name);
105 if (type)
106 s->type = strcpy(type_buf, type);
107
108 service_parse_members(net, s, tb[SERVICE_ATTR_MEMBERS]);
109 avl_insert(&net->services, &s->node);
110 }
111
112 void network_services_add(struct network *net, struct blob_attr *data)
113 {
114 struct blob_attr *cur;
115 int rem;
116
117 blobmsg_for_each_attr(cur, data, rem)
118 service_add(net, cur);
119 }