aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------dtc0
-rw-r--r--io/channel-websock.c264
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/slof.binbin898232 -> 902120 bytes
-rw-r--r--qemu-options.hx38
m---------roms/SLOF0
6 files changed, 237 insertions, 67 deletions
diff --git a/dtc b/dtc
-Subproject ec02b34c05be04f249ffaaca4b666f5246877de
+Subproject fa8bc7f928ac25f23532afc8beb2073efc8fb06
diff --git a/io/channel-websock.c b/io/channel-websock.c
index e47279a1ae..8fabadea2f 100644
--- a/io/channel-websock.c
+++ b/io/channel-websock.c
@@ -33,11 +33,16 @@
#define QIO_CHANNEL_WEBSOCK_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
#define QIO_CHANNEL_WEBSOCK_GUID_LEN strlen(QIO_CHANNEL_WEBSOCK_GUID)
-#define QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL "Sec-WebSocket-Protocol"
-#define QIO_CHANNEL_WEBSOCK_HEADER_VERSION "Sec-WebSocket-Version"
-#define QIO_CHANNEL_WEBSOCK_HEADER_KEY "Sec-WebSocket-Key"
+#define QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL "sec-websocket-protocol"
+#define QIO_CHANNEL_WEBSOCK_HEADER_VERSION "sec-websocket-version"
+#define QIO_CHANNEL_WEBSOCK_HEADER_KEY "sec-websocket-key"
+#define QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE "upgrade"
+#define QIO_CHANNEL_WEBSOCK_HEADER_HOST "host"
+#define QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION "connection"
#define QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY "binary"
+#define QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE "Upgrade"
+#define QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET "websocket"
#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RESPONSE \
"HTTP/1.1 101 Switching Protocols\r\n" \
@@ -49,6 +54,9 @@
#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM "\r\n"
#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_END "\r\n\r\n"
#define QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION "13"
+#define QIO_CHANNEL_WEBSOCK_HTTP_METHOD "GET"
+#define QIO_CHANNEL_WEBSOCK_HTTP_PATH "/"
+#define QIO_CHANNEL_WEBSOCK_HTTP_VERSION "HTTP/1.1"
/* The websockets packet header is variable length
* depending on the size of the payload... */
@@ -99,6 +107,13 @@ struct QEMU_PACKED QIOChannelWebsockHeader {
} u;
};
+typedef struct QIOChannelWebsockHTTPHeader QIOChannelWebsockHTTPHeader;
+
+struct QIOChannelWebsockHTTPHeader {
+ char *name;
+ char *value;
+};
+
enum {
QIO_CHANNEL_WEBSOCK_OPCODE_CONTINUATION = 0x0,
QIO_CHANNEL_WEBSOCK_OPCODE_TEXT_FRAME = 0x1,
@@ -108,25 +123,130 @@ enum {
QIO_CHANNEL_WEBSOCK_OPCODE_PONG = 0xA
};
-static char *qio_channel_websock_handshake_entry(const char *handshake,
- size_t handshake_len,
- const char *name)
-{
- char *begin, *end, *ret = NULL;
- char *line = g_strdup_printf("%s%s: ",
- QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM,
- name);
- begin = g_strstr_len(handshake, handshake_len, line);
- if (begin != NULL) {
- begin += strlen(line);
- end = g_strstr_len(begin, handshake_len - (begin - handshake),
- QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM);
- if (end != NULL) {
- ret = g_strndup(begin, end - begin);
+static size_t
+qio_channel_websock_extract_headers(char *buffer,
+ QIOChannelWebsockHTTPHeader *hdrs,
+ size_t nhdrsalloc,
+ Error **errp)
+{
+ char *nl, *sep, *tmp;
+ size_t nhdrs = 0;
+
+ /*
+ * First parse the HTTP protocol greeting of format:
+ *
+ * $METHOD $PATH $VERSION
+ *
+ * e.g.
+ *
+ * GET / HTTP/1.1
+ */
+
+ nl = strstr(buffer, QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM);
+ if (!nl) {
+ error_setg(errp, "Missing HTTP header delimiter");
+ return 0;
+ }
+ *nl = '\0';
+
+ tmp = strchr(buffer, ' ');
+ if (!tmp) {
+ error_setg(errp, "Missing HTTP path delimiter");
+ return 0;
+ }
+ *tmp = '\0';
+
+ if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_METHOD)) {
+ error_setg(errp, "Unsupported HTTP method %s", buffer);
+ return 0;
+ }
+
+ buffer = tmp + 1;
+ tmp = strchr(buffer, ' ');
+ if (!tmp) {
+ error_setg(errp, "Missing HTTP version delimiter");
+ return 0;
+ }
+ *tmp = '\0';
+
+ if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_PATH)) {
+ error_setg(errp, "Unexpected HTTP path %s", buffer);
+ return 0;
+ }
+
+ buffer = tmp + 1;
+
+ if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_VERSION)) {
+ error_setg(errp, "Unsupported HTTP version %s", buffer);
+ return 0;
+ }
+
+ buffer = nl + strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM);
+
+ /*
+ * Now parse all the header fields of format
+ *
+ * $NAME: $VALUE
+ *
+ * e.g.
+ *
+ * Cache-control: no-cache
+ */
+ do {
+ QIOChannelWebsockHTTPHeader *hdr;
+
+ nl = strstr(buffer, QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM);
+ if (nl) {
+ *nl = '\0';
+ }
+
+ sep = strchr(buffer, ':');
+ if (!sep) {
+ error_setg(errp, "Malformed HTTP header");
+ return 0;
+ }
+ *sep = '\0';
+ sep++;
+ while (*sep == ' ') {
+ sep++;
+ }
+
+ if (nhdrs >= nhdrsalloc) {
+ error_setg(errp, "Too many HTTP headers");
+ return 0;
+ }
+
+ hdr = &hdrs[nhdrs++];
+ hdr->name = buffer;
+ hdr->value = sep;
+
+ /* Canonicalize header name for easier identification later */
+ for (tmp = hdr->name; *tmp; tmp++) {
+ *tmp = g_ascii_tolower(*tmp);
+ }
+
+ if (nl) {
+ buffer = nl + strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM);
+ }
+ } while (nl != NULL);
+
+ return nhdrs;
+}
+
+static const char *
+qio_channel_websock_find_header(QIOChannelWebsockHTTPHeader *hdrs,
+ size_t nhdrs,
+ const char *name)
+{
+ size_t i;
+
+ for (i = 0; i < nhdrs; i++) {
+ if (g_str_equal(hdrs[i].name, name)) {
+ return hdrs[i].value;
}
}
- g_free(line);
- return ret;
+
+ return NULL;
}
@@ -166,58 +286,90 @@ static int qio_channel_websock_handshake_send_response(QIOChannelWebsock *ioc,
}
static int qio_channel_websock_handshake_process(QIOChannelWebsock *ioc,
- const char *line,
- size_t size,
+ char *buffer,
Error **errp)
{
- int ret = -1;
- char *protocols = qio_channel_websock_handshake_entry(
- line, size, QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL);
- char *version = qio_channel_websock_handshake_entry(
- line, size, QIO_CHANNEL_WEBSOCK_HEADER_VERSION);
- char *key = qio_channel_websock_handshake_entry(
- line, size, QIO_CHANNEL_WEBSOCK_HEADER_KEY);
+ QIOChannelWebsockHTTPHeader hdrs[32];
+ size_t nhdrs = G_N_ELEMENTS(hdrs);
+ const char *protocols = NULL, *version = NULL, *key = NULL,
+ *host = NULL, *connection = NULL, *upgrade = NULL;
+ nhdrs = qio_channel_websock_extract_headers(buffer, hdrs, nhdrs, errp);
+ if (!nhdrs) {
+ return -1;
+ }
+
+ protocols = qio_channel_websock_find_header(
+ hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL);
if (!protocols) {
error_setg(errp, "Missing websocket protocol header data");
- goto cleanup;
+ return -1;
}
+ version = qio_channel_websock_find_header(
+ hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_VERSION);
if (!version) {
error_setg(errp, "Missing websocket version header data");
- goto cleanup;
+ return -1;
}
+ key = qio_channel_websock_find_header(
+ hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_KEY);
if (!key) {
error_setg(errp, "Missing websocket key header data");
- goto cleanup;
+ return -1;
+ }
+
+ host = qio_channel_websock_find_header(
+ hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_HOST);
+ if (!host) {
+ error_setg(errp, "Missing websocket host header data");
+ return -1;
+ }
+
+ connection = qio_channel_websock_find_header(
+ hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION);
+ if (!connection) {
+ error_setg(errp, "Missing websocket connection header data");
+ return -1;
+ }
+
+ upgrade = qio_channel_websock_find_header(
+ hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE);
+ if (!upgrade) {
+ error_setg(errp, "Missing websocket upgrade header data");
+ return -1;
}
if (!g_strrstr(protocols, QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY)) {
error_setg(errp, "No '%s' protocol is supported by client '%s'",
QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY, protocols);
- goto cleanup;
+ return -1;
}
if (!g_str_equal(version, QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION)) {
error_setg(errp, "Version '%s' is not supported by client '%s'",
QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION, version);
- goto cleanup;
+ return -1;
}
if (strlen(key) != QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN) {
error_setg(errp, "Key length '%zu' was not as expected '%d'",
strlen(key), QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN);
- goto cleanup;
+ return -1;
}
- ret = qio_channel_websock_handshake_send_response(ioc, key, errp);
+ if (!g_strrstr(connection, QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE)) {
+ error_setg(errp, "No connection upgrade requested '%s'", connection);
+ return -1;
+ }
- cleanup:
- g_free(protocols);
- g_free(version);
- g_free(key);
- return ret;
+ if (!g_str_equal(upgrade, QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET)) {
+ error_setg(errp, "Incorrect upgrade method '%s'", upgrade);
+ return -1;
+ }
+
+ return qio_channel_websock_handshake_send_response(ioc, key, errp);
}
static int qio_channel_websock_handshake_read(QIOChannelWebsock *ioc,
@@ -248,10 +400,10 @@ static int qio_channel_websock_handshake_read(QIOChannelWebsock *ioc,
return 0;
}
}
+ *handshake_end = '\0';
if (qio_channel_websock_handshake_process(ioc,
(char *)ioc->encinput.buffer,
- ioc->encinput.offset,
errp) < 0) {
return -1;
}
@@ -570,21 +722,24 @@ static ssize_t qio_channel_websock_read_wire(QIOChannelWebsock *ioc,
ioc->encinput.offset += ret;
}
- if (ioc->payload_remain == 0) {
- ret = qio_channel_websock_decode_header(ioc, errp);
+ while (ioc->encinput.offset != 0) {
+ if (ioc->payload_remain == 0) {
+ ret = qio_channel_websock_decode_header(ioc, errp);
+ if (ret < 0) {
+ return ret;
+ }
+ if (ret == 0) {
+ ioc->io_eof = TRUE;
+ break;
+ }
+ }
+
+ ret = qio_channel_websock_decode_payload(ioc, errp);
if (ret < 0) {
return ret;
}
- if (ret == 0) {
- return 0;
- }
}
-
- ret = qio_channel_websock_decode_payload(ioc, errp);
- if (ret < 0) {
- return ret;
- }
- return ret;
+ return 1;
}
@@ -642,9 +797,6 @@ static gboolean qio_channel_websock_flush(QIOChannel *ioc,
if (ret < 0) {
goto cleanup;
}
- if (ret == 0) {
- wioc->io_eof = TRUE;
- }
}
cleanup:
diff --git a/pc-bios/README b/pc-bios/README
index 47a913f9c7..dcead369bf 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -17,7 +17,7 @@
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
https://github.com/aik/SLOF, and the image currently in qemu is
- built from git tag qemu-slof-20161019.
+ built from git tag qemu-slof-20170303.
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
index 30ce7ac384..0408723dbf 100644
--- a/pc-bios/slof.bin
+++ b/pc-bios/slof.bin
Binary files differ
diff --git a/qemu-options.hx b/qemu-options.hx
index c85f77d1d8..229243831b 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -144,16 +144,34 @@ STEXI
@item -numa node[,mem=@var{size}][,cpus=@var{firstcpu}[-@var{lastcpu}]][,nodeid=@var{node}]
@itemx -numa node[,memdev=@var{id}][,cpus=@var{firstcpu}[-@var{lastcpu}]][,nodeid=@var{node}]
@findex -numa
-Simulate a multi node NUMA system. If @samp{mem}, @samp{memdev}
-and @samp{cpus} are omitted, resources are split equally. Also, note
-that the -@option{numa} option doesn't allocate any of the specified
-resources. That is, it just assigns existing resources to NUMA nodes. This
-means that one still has to use the @option{-m}, @option{-smp} options
-to allocate RAM and VCPUs respectively, and possibly @option{-object}
-to specify the memory backend for the @samp{memdev} suboption.
-
-@samp{mem} and @samp{memdev} are mutually exclusive. Furthermore, if one
-node uses @samp{memdev}, all of them have to use it.
+Define a NUMA node and assign RAM and VCPUs to it.
+
+@var{firstcpu} and @var{lastcpu} are CPU indexes. Each
+@samp{cpus} option represent a contiguous range of CPU indexes
+(or a single VCPU if @var{lastcpu} is omitted). A non-contiguous
+set of VCPUs can be represented by providing multiple @samp{cpus}
+options. If @samp{cpus} is omitted on all nodes, VCPUs are automatically
+split between them.
+
+For example, the following option assigns VCPUs 0, 1, 2 and 5 to
+a NUMA node:
+@example
+-numa node,cpus=0-2,cpus=5
+@end example
+
+@samp{mem} assigns a given RAM amount to a node. @samp{memdev}
+assigns RAM from a given memory backend device to a node. If
+@samp{mem} and @samp{memdev} are omitted in all nodes, RAM is
+split equally between them.
+
+@samp{mem} and @samp{memdev} are mutually exclusive. Furthermore,
+if one node uses @samp{memdev}, all of them have to use it.
+
+Note that the -@option{numa} option doesn't allocate any of the
+specified resources, it just assigns existing resources to NUMA
+nodes. This means that one still has to use the @option{-m},
+@option{-smp} options to allocate RAM and VCPUs respectively.
+
ETEXI
DEF("add-fd", HAS_ARG, QEMU_OPTION_add_fd,
diff --git a/roms/SLOF b/roms/SLOF
-Subproject efd65f49929d7db775b26066d538c8120ae3db9
+Subproject 66d250ef0fd06bb88b7399b9563b5008201f2d6