minstrel-rcd: add work-in-progress minstrel remote control daemon
[openwrt/staging/nbd.git] / package / utils / minstrel-rcd / src / server.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> */
3 #include <sys/socket.h>
4 #include <netinet/in.h>
5 #include <errno.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8
9 #include <libubox/usock.h>
10
11 #include "rcd.h"
12
13 static LIST_HEAD(servers);
14 static LIST_HEAD(pending);
15 static bool in_init;
16 static struct uloop_timeout restart_timer;
17
18 static void
19 server_cb(struct uloop_fd *fd, unsigned int events)
20 {
21 struct server *s = container_of(fd, struct server, fd);
22 struct sockaddr_in6 addr;
23 unsigned int sl;
24 int cfd;
25
26 while (1) {
27 sl = sizeof(addr);
28 cfd = accept(fd->fd, (struct sockaddr *)&addr, &sl);
29
30 if (cfd < 0) {
31 if (errno == EAGAIN)
32 return;
33
34 if (errno == EINTR)
35 continue;
36
37 /* other error, restart */
38 uloop_fd_delete(fd);
39 close(fd->fd);
40 list_move_tail(&s->list, &pending);
41 uloop_timeout_set(&restart_timer, 1000);
42 }
43
44 rcd_client_accept(cfd);
45 }
46 }
47
48 static void server_start(struct server *s)
49 {
50 s->fd.fd = usock(USOCK_SERVER | USOCK_NONBLOCK | USOCK_TCP, s->addr, usock_port(RCD_PORT));
51 if (s->fd.fd < 0) {
52 if (in_init)
53 fprintf(stderr, "WARNING: Failed to open server port on %s\n", s->addr);
54 return;
55 }
56
57 s->fd.cb = server_cb;
58 uloop_fd_add(&s->fd, ULOOP_READ);
59 list_move_tail(&s->list, &servers);
60 }
61
62 static void
63 server_start_pending(struct uloop_timeout *timeout)
64 {
65 struct server *s, *tmp;
66
67 list_for_each_entry_safe(s, tmp, &pending, list)
68 server_start(s);
69
70 if (!list_empty(&pending))
71 uloop_timeout_set(timeout, 1000);
72 }
73
74 void rcd_server_add(const char *addr)
75 {
76 struct server *s;
77
78 s = calloc(1, sizeof(*s));
79 s->addr = addr;
80 list_add_tail(&s->list, &pending);
81
82 }
83
84 void rcd_server_init(void)
85 {
86 if (list_empty(&pending))
87 rcd_server_add("127.0.0.1");
88
89 restart_timer.cb = server_start_pending;
90
91 in_init = true;
92 server_start_pending(&restart_timer);
93 in_init = false;
94 }