8358f06a320a9e716e10318740326de52f6fdd94
[petitboot] / discover / discover-server.c
1
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <stdint.h>
6 #include <errno.h>
7 #include <assert.h>
8
9 #include <sys/socket.h>
10 #include <sys/un.h>
11 #include <asm/byteorder.h>
12
13 #include <talloc/talloc.h>
14
15 #include "ui/common/device.h"
16 #include "pb-protocol/pb-protocol.h"
17 #include "list/list.h"
18
19 #include "log.h"
20 #include "waiter.h"
21
22 struct discover_server {
23         int socket;
24         struct waiter *waiter;
25         struct list clients;
26 };
27
28 struct client {
29         struct list_item list;
30         int fd;
31 };
32
33
34 static int server_destructor(void *arg)
35 {
36         struct discover_server *server = arg;
37
38         if (server->waiter)
39                 waiter_unregister(server->waiter);
40
41         if (server->socket >= 0)
42                 close(server->socket);
43
44         return 0;
45 }
46
47 static int client_destructor(void *arg)
48 {
49         struct client *client = arg;
50
51         if (client->fd >= 0)
52                 close(client->fd);
53
54         list_remove(&client->list);
55
56         return 0;
57
58 }
59
60 static void print_clients(struct discover_server *server)
61         __attribute__((unused));
62
63 static void print_clients(struct discover_server *server)
64 {
65         struct client *client;
66
67         printf("current clients [%p,%p,%p]:\n",
68                         &server->clients.head,
69                         server->clients.head.prev,
70                         server->clients.head.next);
71         list_for_each_entry(&server->clients, client, list)
72                 printf("\t[%p,%p,%p] client: %d\n", &client->list,
73                                 client->list.prev, client->list.next,
74                                 client->fd);
75 }
76
77 static struct boot_option options[] = {
78         {
79                 .id = "1.1",
80                 .name = "meep one",
81                 .description = "meep description one",
82                 .icon_file = "meep.one.png",
83                 .boot_args = "root=/dev/sda1",
84         },
85 };
86
87 static struct device device = {
88         .id = "1",
89         .name = "meep",
90         .description = "meep description",
91         .icon_file = "meep.png",
92         .n_options = 1,
93         .options = options,
94 };
95
96 static int client_write_message(struct discover_server *server,
97                 struct client *client, struct pb_protocol_message *message)
98 {
99         int rc;
100
101         rc = pb_protocol_write_message(client->fd, message);
102         if (rc)
103                 talloc_free(client);
104
105         return rc;
106 }
107
108 static int write_add_message(struct discover_server *server,
109                 struct client *client, struct device *dev)
110 {
111         struct pb_protocol_message *message;
112         int len;
113
114         len = pb_protocol_device_len(dev);
115
116         message = pb_protocol_create_message(client,
117                         PB_PROTOCOL_ACTION_ADD, len);
118         if (!message)
119                 return -1;
120
121         pb_protocol_serialise_device(dev, message->payload, len);
122
123         return client_write_message(server, client, message);
124 }
125
126 static int write_remove_message(struct discover_server *server,
127                 struct client *client, char *dev_id)
128 {
129         struct pb_protocol_message *message;
130         int len;
131
132         len = strlen(dev_id) + sizeof(uint32_t);
133
134         message = pb_protocol_create_message(client,
135                         PB_PROTOCOL_ACTION_REMOVE, len);
136         if (!message)
137                 return -1;
138
139         pb_protocol_serialise_string(message->payload, dev_id);
140
141         return client_write_message(server, client, message);
142 }
143
144 static int discover_server_process(void *arg)
145 {
146         struct discover_server *server = arg;
147         struct client *client;
148         int fd;
149
150
151         len = sizeof(addr);
152
153         /* accept the incoming connection */
154         fd = accept(server->socket, NULL, 0);
155         if (!fd) {
156                 pb_log("accept: %s\n", strerror(errno));
157                 return 0;
158         }
159
160         /* add to our list of clients */
161         client = talloc(server, struct client);
162         list_add(&server->clients, &client->list);
163
164         talloc_set_destructor(client, client_destructor);
165
166         client->fd = fd;
167
168         /* send existing devices to client */
169         write_add_message(server, client, &device);
170
171         sleep(2);
172
173         write_remove_message(server, client, "1");
174
175         return 0;
176 }
177
178 struct discover_server *discover_server_init(void)
179 {
180         struct discover_server *server;
181         struct sockaddr_un addr;
182
183         server = talloc(NULL, struct discover_server);
184         if (!server)
185                 return NULL;
186
187         server->waiter = NULL;
188         list_init(&server->clients);
189
190         unlink(PB_SOCKET_PATH);
191
192         server->socket = socket(AF_UNIX, SOCK_STREAM, 0);
193         if (server->socket < 0) {
194                 pb_log("error creating server socket: %s\n", strerror(errno));
195                 goto out_err;
196         }
197
198         talloc_set_destructor(server, server_destructor);
199
200         addr.sun_family = AF_UNIX;
201         strcpy(addr.sun_path, PB_SOCKET_PATH);
202
203         if (bind(server->socket, (struct sockaddr *)&addr, sizeof(addr))) {
204                 pb_log("error binding server socket: %s\n", strerror(errno));
205                 goto out_err;
206         }
207
208         if (listen(server->socket, 8)) {
209                 pb_log("server socket listen: %s\n", strerror(errno));
210                 goto out_err;
211         }
212
213         server->waiter = waiter_register(server->socket, WAIT_IN,
214                         discover_server_process, server);
215
216         return server;
217
218 out_err:
219         talloc_free(server);
220         return NULL;
221 }
222
223 void discover_server_destroy(struct discover_server *server)
224 {
225         talloc_free(server);
226 }
227