summaryrefslogtreecommitdiffstats
path: root/lib/pb-protocol
diff options
context:
space:
mode:
authorJeremy Kerr <jk@ozlabs.org>2008-12-15 15:22:34 +1100
committerJeremy Kerr <jk@ozlabs.org>2008-12-15 15:22:34 +1100
commit32e6a41f33e5576716b351bd473a27939fe94fa1 (patch)
tree0d6b75ac0a02d2496416095405cb9498777c3beb /lib/pb-protocol
parent000a92b4fa909c432732ac3ed8f28eeeaeac70ee (diff)
downloadpetitboot-32e6a41f33e5576716b351bd473a27939fe94fa1.zip
petitboot-32e6a41f33e5576716b351bd473a27939fe94fa1.tar.gz
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 'lib/pb-protocol')
-rw-r--r--lib/pb-protocol/pb-protocol.c307
-rw-r--r--lib/pb-protocol/pb-protocol.h57
2 files changed, 364 insertions, 0 deletions
diff --git a/lib/pb-protocol/pb-protocol.c b/lib/pb-protocol/pb-protocol.c
new file mode 100644
index 0000000..2fd76c5
--- /dev/null
+++ b/lib/pb-protocol/pb-protocol.c
@@ -0,0 +1,307 @@
+
+#include <string.h>
+#include <stdint.h>
+#include <asm/byteorder.h>
+
+#include <talloc/talloc.h>
+
+#include "pb-protocol.h"
+
+
+/* Message format:
+ *
+ * 4-byte action, determines the remaining message content
+ * 4-byte total payload len
+ * - not including action and payload len header
+ *
+ * action = 0x1: device add message
+ * payload:
+ * 4-byte len, id
+ * 4-byte len, name
+ * 4-byte len, description
+ * 4-byte len, icon_file
+ *
+ * 4-byte option count
+ * for each option:
+ * 4-byte len, id
+ * 4-byte len, name
+ * 4-byte len, description
+ * 4-byte len, icon_file
+ * 4-byte len, boot_image_file
+ * 4-byte len, initrd_file
+ * 4-byte len, boot_args
+ *
+ * action = 0x2: device remove message
+ * payload:
+ * 4-byte len, id
+ */
+
+
+/* Write a string into the buffer, starting at pos.
+ *
+ * Returns the total length used for the write, including length header.
+ */
+int pb_protocol_serialise_string(char *pos, const char *str)
+{
+ int len = 0;
+
+ if (str)
+ len = strlen(str);
+
+ *(uint32_t *)pos = __cpu_to_be32(len);
+ pos += sizeof(uint32_t);
+
+ memcpy(pos, str, len);
+
+ return len + sizeof(uint32_t);
+}
+
+/* Read a string from a buffer, allocating the new string as necessary.
+ *
+ * @param[in] ctx The talloc context to base the allocation on
+ * @param[in,out] pos Where to start reading
+ * @param[in,out] len The amount of data remaining in the buffer
+ * @param[out] str Pointer to resuling string
+ * @return zero on success, non-zero on failure
+ */
+static int read_string(void *ctx, char **pos, int *len, char **str)
+{
+ uint32_t str_len, read_len;
+
+ if (*len < sizeof(uint32_t))
+ return -1;
+
+ str_len = __be32_to_cpu(*(uint32_t *)(*pos));
+ read_len = sizeof(uint32_t);
+
+ if (read_len + str_len > *len)
+ return -1;
+
+ if (str_len == 0)
+ *str = NULL;
+ else
+ *str = talloc_strndup(ctx, *pos + read_len, str_len);
+
+ read_len += str_len;
+
+ /* all ok, update the caller's pointers */
+ *pos += read_len;
+ *len -= read_len;
+
+ return 0;
+}
+
+char *pb_protocol_deserialise_string(void *ctx,
+ struct pb_protocol_message *message)
+{
+ char *buf, *str;
+ int len;
+
+ len = message->payload_len;
+ buf = message->payload;
+
+ if (read_string(ctx, &buf, &len, &str))
+ return NULL;
+
+ return str;
+}
+
+static int optional_strlen(const char *str)
+{
+ if (!str)
+ return 0;
+ return strlen(str);
+}
+
+int pb_protocol_device_len(struct device *dev)
+{
+ int len, i;
+
+ len = 4 + optional_strlen(dev->id) +
+ 4 + optional_strlen(dev->name) +
+ 4 + optional_strlen(dev->description) +
+ 4 + optional_strlen(dev->icon_file) +
+ 4;
+
+ for (i = 0; i < dev->n_options; i++) {
+ struct boot_option *opt = &dev->options[i];
+ len += 4 + optional_strlen(opt->id) +
+ 4 + optional_strlen(opt->name) +
+ 4 + optional_strlen(opt->description) +
+ 4 + optional_strlen(opt->icon_file) +
+ 4 + optional_strlen(opt->boot_image_file) +
+ 4 + optional_strlen(opt->initrd_file) +
+ 4 + optional_strlen(opt->boot_args);
+ }
+
+ return len;
+}
+
+int pb_protocol_serialise_device(struct device *dev, char *buf, int buf_len)
+{
+ char *pos;
+ int i;
+
+ pos = buf;
+
+ /* construct payload into buffer */
+ pos += pb_protocol_serialise_string(pos, dev->id);
+ pos += pb_protocol_serialise_string(pos, dev->name);
+ pos += pb_protocol_serialise_string(pos, dev->description);
+ pos += pb_protocol_serialise_string(pos, dev->icon_file);
+
+ /* write option count */
+ *(uint32_t *)pos = __cpu_to_be32(dev->n_options);
+ pos += sizeof(uint32_t);
+
+ /* write each option */
+ for (i = 0; i < dev->n_options; i++) {
+ struct boot_option *opt = &dev->options[i];
+ pos += pb_protocol_serialise_string(pos, opt->id);
+ pos += pb_protocol_serialise_string(pos, opt->name);
+ pos += pb_protocol_serialise_string(pos, opt->description);
+ pos += pb_protocol_serialise_string(pos, opt->icon_file);
+ pos += pb_protocol_serialise_string(pos, opt->boot_image_file);
+ pos += pb_protocol_serialise_string(pos, opt->initrd_file);
+ pos += pb_protocol_serialise_string(pos, opt->boot_args);
+ }
+
+ return 0;
+}
+
+int pb_protocol_write_message(int fd, struct pb_protocol_message *message)
+{
+ int total_len, rc;
+ char *pos;
+
+ total_len = sizeof(*message) + message->payload_len;
+
+ message->payload_len = __cpu_to_be32(message->payload_len);
+ message->action = __cpu_to_be32(message->action);
+
+ for (pos = (void *)message; total_len;) {
+ rc = write(fd, pos, total_len);
+
+ if (rc <= 0)
+ break;
+
+ total_len -= rc;
+ pos += rc;
+ }
+
+ talloc_free(message);
+
+ return total_len ? -1 : 0;
+}
+
+struct pb_protocol_message *pb_protocol_create_message(void *ctx,
+ int action, int payload_len)
+{
+ struct pb_protocol_message *message;
+
+ if (payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE)
+ return NULL;
+
+ message = talloc_size(ctx, sizeof(*message) + payload_len);
+
+ /* we convert these to big-endian in write_message() */
+ message->action = action;
+ message->payload_len = payload_len;
+
+ return message;
+
+}
+
+struct pb_protocol_message *pb_protocol_read_message(void *ctx, int fd)
+{
+ struct pb_protocol_message *message, m;
+ int rc, len;
+
+ /* use the stack for the initial 8-byte read */
+
+ rc = read(fd, &m, sizeof(m));
+ if (rc != sizeof(m))
+ return NULL;
+
+ m.payload_len = __be32_to_cpu(m.payload_len);
+ m.action = __be32_to_cpu(m.action);
+
+ if (m.payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE)
+ return NULL;
+
+ message = talloc_size(ctx, sizeof(m) + m.payload_len);
+ memcpy(message, &m, sizeof(m));
+
+ for (len = 0; len < m.payload_len;) {
+ rc = read(fd, message->payload + len, m.payload_len - len);
+
+ if (rc <= 0) {
+ talloc_free(message);
+ return NULL;
+ }
+
+ len += rc;
+ }
+
+ return message;
+}
+
+
+struct device *pb_protocol_deserialise_device(void *ctx,
+ struct pb_protocol_message *message)
+{
+ struct device *dev;
+ char *pos;
+ int i, len;
+
+ len = message->payload_len;
+ pos = message->payload;
+
+ dev = talloc(ctx, struct device);
+
+ if (read_string(dev, &pos, &len, &dev->id))
+ goto out_err;
+
+ if (read_string(dev, &pos, &len, &dev->name))
+ goto out_err;
+
+ if (read_string(dev, &pos, &len, &dev->description))
+ goto out_err;
+
+ if (read_string(dev, &pos, &len, &dev->icon_file))
+ goto out_err;
+
+ dev->n_options = __be32_to_cpu(*(uint32_t *)pos);
+ dev->options = talloc_array(dev, struct boot_option, dev->n_options);
+ pos += sizeof(uint32_t);
+
+ for (i = 0; i < dev->n_options; i++) {
+ struct boot_option *opt = &dev->options[i];
+
+ if (read_string(opt, &pos, &len, &opt->id))
+ goto out_err;
+ if (read_string(opt, &pos, &len, &opt->name))
+ goto out_err;
+ if (read_string(opt, &pos, &len,
+ &opt->description))
+ goto out_err;
+ if (read_string(opt, &pos, &len,
+ &opt->icon_file))
+ goto out_err;
+ if (read_string(opt, &pos, &len,
+ &opt->boot_image_file))
+ goto out_err;
+ if (read_string(opt, &pos, &len,
+ &opt->initrd_file))
+ goto out_err;
+ if (read_string(opt, &pos, &len,
+ &opt->boot_args))
+ goto out_err;
+ }
+
+ return dev;
+
+out_err:
+ talloc_free(dev);
+ return NULL;
+}
diff --git a/lib/pb-protocol/pb-protocol.h b/lib/pb-protocol/pb-protocol.h
new file mode 100644
index 0000000..7b557d6
--- /dev/null
+++ b/lib/pb-protocol/pb-protocol.h
@@ -0,0 +1,57 @@
+#ifndef _PB_PROTOCOL_H
+#define _PB_PROTOCOL_H
+
+#include <stdint.h>
+
+#define PB_SOCKET_PATH "/tmp/petitboot.ui"
+
+#define PB_PROTOCOL_MAX_PAYLOAD_SIZE 4096
+
+enum pb_protocol_action {
+ PB_PROTOCOL_ACTION_ADD = 0x1,
+ PB_PROTOCOL_ACTION_REMOVE = 0x2,
+};
+
+struct pb_protocol_message {
+ uint32_t action;
+ uint32_t payload_len;
+ char payload[];
+};
+
+struct device {
+ char *id;
+ char *name;
+ char *description;
+ char *icon_file;
+
+ struct boot_option {
+ char *id;
+ char *name;
+ char *description;
+ char *icon_file;
+ char *boot_image_file;
+ char *initrd_file;
+ char *boot_args;
+ } *options;
+ int n_options;
+};
+
+int pb_protocol_device_len(struct device *dev);
+
+int pb_protocol_serialise_string(char *pos, const char *str);
+char *pb_protocol_deserialise_string(void *ctx,
+ struct pb_protocol_message *message);
+
+int pb_protocol_serialise_device(struct device *dev, char *buf, int buf_len);
+
+int pb_protocol_write_message(int fd, struct pb_protocol_message *message);
+
+struct pb_protocol_message *pb_protocol_create_message(void *ctx,
+ int action, int payload_len);
+
+struct pb_protocol_message *pb_protocol_read_message(void *ctx, int fd);
+
+struct device *pb_protocol_deserialise_device(void *ctx,
+ struct pb_protocol_message *message);
+
+#endif /* _PB_PROTOCOL_H */
OpenPOWER on IntegriCloud