diff options
author | Jeremy Kerr <jk@ozlabs.org> | 2008-12-15 15:22:34 +1100 |
---|---|---|
committer | Jeremy Kerr <jk@ozlabs.org> | 2008-12-15 15:22:34 +1100 |
commit | 32e6a41f33e5576716b351bd473a27939fe94fa1 (patch) | |
tree | 0d6b75ac0a02d2496416095405cb9498777c3beb /discover/discover-server.c | |
parent | 000a92b4fa909c432732ac3ed8f28eeeaeac70ee (diff) | |
download | talos-petitboot-32e6a41f33e5576716b351bd473a27939fe94fa1.tar.gz talos-petitboot-32e6a41f33e5576716b351bd473a27939fe94fa1.zip |
Initial support for multiple UIs
Move the device discovery code from separate udev helpers to a single
process to listen on two sockets: one SOCK_DGRAM for incoming udev
events, and one SOCK_STREAM for UIs to connect.
Initial support for client/server infrastructure, still need to wire-up
the udev messages.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Diffstat (limited to 'discover/discover-server.c')
-rw-r--r-- | discover/discover-server.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/discover/discover-server.c b/discover/discover-server.c new file mode 100644 index 0000000..8358f06 --- /dev/null +++ b/discover/discover-server.c @@ -0,0 +1,227 @@ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <errno.h> +#include <assert.h> + +#include <sys/socket.h> +#include <sys/un.h> +#include <asm/byteorder.h> + +#include <talloc/talloc.h> + +#include "ui/common/device.h" +#include "pb-protocol/pb-protocol.h" +#include "list/list.h" + +#include "log.h" +#include "waiter.h" + +struct discover_server { + int socket; + struct waiter *waiter; + struct list clients; +}; + +struct client { + struct list_item list; + int fd; +}; + + +static int server_destructor(void *arg) +{ + struct discover_server *server = arg; + + if (server->waiter) + waiter_unregister(server->waiter); + + if (server->socket >= 0) + close(server->socket); + + return 0; +} + +static int client_destructor(void *arg) +{ + struct client *client = arg; + + if (client->fd >= 0) + close(client->fd); + + list_remove(&client->list); + + return 0; + +} + +static void print_clients(struct discover_server *server) + __attribute__((unused)); + +static void print_clients(struct discover_server *server) +{ + struct client *client; + + printf("current clients [%p,%p,%p]:\n", + &server->clients.head, + server->clients.head.prev, + server->clients.head.next); + list_for_each_entry(&server->clients, client, list) + printf("\t[%p,%p,%p] client: %d\n", &client->list, + client->list.prev, client->list.next, + client->fd); +} + +static struct boot_option options[] = { + { + .id = "1.1", + .name = "meep one", + .description = "meep description one", + .icon_file = "meep.one.png", + .boot_args = "root=/dev/sda1", + }, +}; + +static struct device device = { + .id = "1", + .name = "meep", + .description = "meep description", + .icon_file = "meep.png", + .n_options = 1, + .options = options, +}; + +static int client_write_message(struct discover_server *server, + struct client *client, struct pb_protocol_message *message) +{ + int rc; + + rc = pb_protocol_write_message(client->fd, message); + if (rc) + talloc_free(client); + + return rc; +} + +static int write_add_message(struct discover_server *server, + struct client *client, struct device *dev) +{ + struct pb_protocol_message *message; + int len; + + len = pb_protocol_device_len(dev); + + message = pb_protocol_create_message(client, + PB_PROTOCOL_ACTION_ADD, len); + if (!message) + return -1; + + pb_protocol_serialise_device(dev, message->payload, len); + + return client_write_message(server, client, message); +} + +static int write_remove_message(struct discover_server *server, + struct client *client, char *dev_id) +{ + struct pb_protocol_message *message; + int len; + + len = strlen(dev_id) + sizeof(uint32_t); + + message = pb_protocol_create_message(client, + PB_PROTOCOL_ACTION_REMOVE, len); + if (!message) + return -1; + + pb_protocol_serialise_string(message->payload, dev_id); + + return client_write_message(server, client, message); +} + +static int discover_server_process(void *arg) +{ + struct discover_server *server = arg; + struct client *client; + int fd; + + + len = sizeof(addr); + + /* accept the incoming connection */ + fd = accept(server->socket, NULL, 0); + if (!fd) { + pb_log("accept: %s\n", strerror(errno)); + return 0; + } + + /* add to our list of clients */ + client = talloc(server, struct client); + list_add(&server->clients, &client->list); + + talloc_set_destructor(client, client_destructor); + + client->fd = fd; + + /* send existing devices to client */ + write_add_message(server, client, &device); + + sleep(2); + + write_remove_message(server, client, "1"); + + return 0; +} + +struct discover_server *discover_server_init(void) +{ + struct discover_server *server; + struct sockaddr_un addr; + + server = talloc(NULL, struct discover_server); + if (!server) + return NULL; + + server->waiter = NULL; + list_init(&server->clients); + + unlink(PB_SOCKET_PATH); + + server->socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (server->socket < 0) { + pb_log("error creating server socket: %s\n", strerror(errno)); + goto out_err; + } + + talloc_set_destructor(server, server_destructor); + + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, PB_SOCKET_PATH); + + if (bind(server->socket, (struct sockaddr *)&addr, sizeof(addr))) { + pb_log("error binding server socket: %s\n", strerror(errno)); + goto out_err; + } + + if (listen(server->socket, 8)) { + pb_log("server socket listen: %s\n", strerror(errno)); + goto out_err; + } + + server->waiter = waiter_register(server->socket, WAIT_IN, + discover_server_process, server); + + return server; + +out_err: + talloc_free(server); + return NULL; +} + +void discover_server_destroy(struct discover_server *server) +{ + talloc_free(server); +} + |