ucode: check for errors in ftruncate()
[project/udebug.git] / ring.c
1 #include "server.h"
2
3 static FILE *urandom;
4
5 AVL_TREE(rings, udebug_id_cmp, true, NULL);
6
7 struct client_ring *client_ring_get_by_id(struct client *cl, uint32_t id)
8 {
9 struct client_ring *r;
10
11 list_for_each_entry(r, &cl->bufs, list)
12 if (r->id == id)
13 return r;
14
15 return NULL;
16 }
17
18 static uint32_t gen_ring_id(void)
19 {
20 uint32_t val = 0;
21
22 if (!urandom && (urandom = fopen("/dev/urandom", "r")) == NULL)
23 return 0;
24
25 if (fread(&val, sizeof(val), 1, urandom) != 1)
26 return 0;
27
28 return val;
29 }
30
31 struct client_ring *client_ring_alloc(struct client *cl)
32 {
33 enum {
34 RING_ATTR_NAME,
35 RING_ATTR_FLAGS,
36 __RING_ATTR_MAX,
37 };
38 static const struct blobmsg_policy policy[__RING_ATTR_MAX] = {
39 [RING_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
40 [RING_ATTR_FLAGS] = { "flags", BLOBMSG_TYPE_ARRAY },
41 };
42 struct udebug_client_msg *msg = &cl->rx_buf.msg;
43 struct blob_attr *tb[__RING_ATTR_MAX], *meta;
44 struct client_ring *r;
45 size_t meta_len;
46
47 if (cl->rx_fd < 0) {
48 DC(2, cl, "missing file descriptor");
49 return NULL;
50 }
51
52 meta_len = blob_pad_len(&cl->rx_buf.data);
53 r = calloc_a(sizeof(*r), &meta, meta_len);
54 memcpy(meta, cl->rx_buf.buf, meta_len);
55
56 blobmsg_parse_attr(policy, __RING_ATTR_MAX, tb, meta);
57 if (!tb[RING_ATTR_NAME]) {
58 DC(2, cl, "missing ring name");
59 close(cl->rx_fd);
60 free(r);
61 return NULL;
62 }
63
64 r->name = blobmsg_get_string(tb[RING_ATTR_NAME]);
65 r->flags = tb[RING_ATTR_FLAGS];
66
67 r->cl = cl;
68 r->id = msg->id;
69 r->fd = cl->rx_fd;
70 cl->rx_fd = -1;
71 r->ring_size = msg->ring_size;
72 r->data_size = msg->data_size;
73 list_add_tail(&r->list, &cl->bufs);
74
75 r->node.key = (void *)(uintptr_t)gen_ring_id();
76 avl_insert(&rings, &r->node);
77 udebug_ubus_ring_notify(r, true);
78 DC(2, cl, "add ring %d [%x] ring_size=%x data_size=%x", r->id, ring_id(r), r->ring_size, r->data_size);
79
80 return r;
81 }
82
83 void client_ring_free(struct client_ring *r)
84 {
85 DC(2, r->cl, "free ring %d [%x]", r->id, ring_id(r));
86 udebug_ubus_ring_notify(r, false);
87 avl_delete(&rings, &r->node);
88 list_del(&r->list);
89 close(r->fd);
90 free(r);
91 }