From nobody Sat May 4 17:16:08 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1507120259697684.7905811164276; Wed, 4 Oct 2017 05:30:59 -0700 (PDT) Received: from localhost ([::1]:34968 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzipB-00072p-Vm for importer@patchew.org; Wed, 04 Oct 2017 08:30:54 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55142) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzijv-0002kH-Oh for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dzijq-0005GP-K4 for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:27 -0400 Received: from mx1.redhat.com ([209.132.183.28]:43372) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dzijq-0005FZ-Ah for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:22 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2A54E5F2976; Wed, 4 Oct 2017 12:25:21 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0023B5C1A1; Wed, 4 Oct 2017 12:25:19 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 2A54E5F2976 Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=berrange@redhat.com From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Wed, 4 Oct 2017 13:25:05 +0100 Message-Id: <20171004122515.20627-2-berrange@redhat.com> In-Reply-To: <20171004122515.20627-1-berrange@redhat.com> References: <20171004122515.20627-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Wed, 04 Oct 2017 12:25:21 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v1 01/11] io: send proper HTTP response for websocket errors X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" When any error occurs while processing the websockets handshake, QEMU just terminates the connection abruptly. This is in violation of the HTTP specs and does not help the client understand what they did wrong. This is particularly bad when the client gives the wrong path, as a "404 Not Found" would be very helpful. Refactor the handshake code so that it always sends a response to the client unless there was an I/O error. Fixes bug: #1715186 Reviewed-by: Philippe Mathieu-Daud=C3=A9 Signed-off-by: Daniel P. Berrange --- io/channel-websock.c | 185 ++++++++++++++++++++++++++++++++++++++---------= ---- 1 file changed, 139 insertions(+), 46 deletions(-) diff --git a/io/channel-websock.c b/io/channel-websock.c index 5a3badbec2..f5fac5b422 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -25,6 +25,8 @@ #include "crypto/hash.h" #include "trace.h" =20 +#include + =20 /* Max amount to allow in rawinput/rawoutput buffers */ #define QIO_CHANNEL_WEBSOCK_MAX_BUFFER 8192 @@ -44,13 +46,40 @@ #define QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE "Upgrade" #define QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET "websocket" =20 -#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RESPONSE \ +#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ + "Server: QEMU VNC\r\n" \ + "Date: %s\r\n" + +#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_OK \ "HTTP/1.1 101 Switching Protocols\r\n" \ + QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ "Upgrade: websocket\r\n" \ "Connection: Upgrade\r\n" \ "Sec-WebSocket-Accept: %s\r\n" \ "Sec-WebSocket-Protocol: binary\r\n" \ "\r\n" +#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_NOT_FOUND \ + "HTTP/1.1 404 Not Found\r\n" \ + QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ + "Connection: close\r\n" \ + "\r\n" +#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST \ + "HTTP/1.1 400 Bad Request\r\n" \ + QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ + "Connection: close\r\n" \ + "Sec-WebSocket-Version: " \ + QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION \ + "\r\n" +#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_SERVER_ERR \ + "HTTP/1.1 500 Internal Server Error\r\n" \ + QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ + "Connection: close\r\n" \ + "\r\n" +#define QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_TOO_LARGE \ + "HTTP/1.1 403 Request Entity Too Large\r\n" \ + QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_COMMON \ + "Connection: close\r\n" \ + "\r\n" #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" @@ -123,8 +152,46 @@ enum { QIO_CHANNEL_WEBSOCK_OPCODE_PONG =3D 0xA }; =20 +static void qio_channel_websock_handshake_send_res(QIOChannelWebsock *ioc, + const char *resmsg, + ...) +{ + va_list vargs; + char *response; + size_t responselen; + + va_start(vargs, resmsg); + response =3D g_strdup_vprintf(resmsg, vargs); + responselen =3D strlen(response); + buffer_reserve(&ioc->encoutput, responselen); + buffer_append(&ioc->encoutput, response, responselen); + va_end(vargs); +} + +static gchar *qio_channel_websock_date_str(void) +{ + struct tm tm; + time_t now =3D time(NULL); + char datebuf[128]; + + gmtime_r(&now, &tm); + + strftime(datebuf, sizeof(datebuf), "%a, %d %b %Y %H:%M:%S GMT", &tm); + + return g_strdup(datebuf); +} + +static void qio_channel_websock_handshake_send_res_err(QIOChannelWebsock *= ioc, + const char *resdata) +{ + char *date =3D qio_channel_websock_date_str(); + qio_channel_websock_handshake_send_res(ioc, resdata, date); + g_free(date); +} + static size_t -qio_channel_websock_extract_headers(char *buffer, +qio_channel_websock_extract_headers(QIOChannelWebsock *ioc, + char *buffer, QIOChannelWebsockHTTPHeader *hdrs, size_t nhdrsalloc, Error **errp) @@ -145,7 +212,7 @@ qio_channel_websock_extract_headers(char *buffer, nl =3D strstr(buffer, QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM); if (!nl) { error_setg(errp, "Missing HTTP header delimiter"); - return 0; + goto bad_request; } *nl =3D '\0'; =20 @@ -158,18 +225,20 @@ qio_channel_websock_extract_headers(char *buffer, =20 if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_METHOD)) { error_setg(errp, "Unsupported HTTP method %s", buffer); - return 0; + goto bad_request; } =20 buffer =3D tmp + 1; tmp =3D strchr(buffer, ' '); if (!tmp) { error_setg(errp, "Missing HTTP version delimiter"); - return 0; + goto bad_request; } *tmp =3D '\0'; =20 if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_PATH)) { + qio_channel_websock_handshake_send_res_err( + ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_NOT_FOUND); error_setg(errp, "Unexpected HTTP path %s", buffer); return 0; } @@ -178,7 +247,7 @@ qio_channel_websock_extract_headers(char *buffer, =20 if (!g_str_equal(buffer, QIO_CHANNEL_WEBSOCK_HTTP_VERSION)) { error_setg(errp, "Unsupported HTTP version %s", buffer); - return 0; + goto bad_request; } =20 buffer =3D nl + strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_DELIM); @@ -203,7 +272,7 @@ qio_channel_websock_extract_headers(char *buffer, sep =3D strchr(buffer, ':'); if (!sep) { error_setg(errp, "Malformed HTTP header"); - return 0; + goto bad_request; } *sep =3D '\0'; sep++; @@ -213,7 +282,7 @@ qio_channel_websock_extract_headers(char *buffer, =20 if (nhdrs >=3D nhdrsalloc) { error_setg(errp, "Too many HTTP headers"); - return 0; + goto bad_request; } =20 hdr =3D &hdrs[nhdrs++]; @@ -231,6 +300,11 @@ qio_channel_websock_extract_headers(char *buffer, } while (nl !=3D NULL); =20 return nhdrs; + + bad_request: + qio_channel_websock_handshake_send_res_err( + ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST); + return 0; } =20 static const char * @@ -250,14 +324,14 @@ qio_channel_websock_find_header(QIOChannelWebsockHTTP= Header *hdrs, } =20 =20 -static int qio_channel_websock_handshake_send_response(QIOChannelWebsock *= ioc, - const char *key, - Error **errp) +static void qio_channel_websock_handshake_send_res_ok(QIOChannelWebsock *i= oc, + const char *key, + Error **errp) { char combined_key[QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + QIO_CHANNEL_WEBSOCK_GUID_LEN + 1]; - char *accept =3D NULL, *response =3D NULL; - size_t responselen; + char *accept =3D NULL; + char *date =3D qio_channel_websock_date_str(); =20 g_strlcpy(combined_key, key, QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN + 1); g_strlcat(combined_key, QIO_CHANNEL_WEBSOCK_GUID, @@ -271,105 +345,108 @@ static int qio_channel_websock_handshake_send_respo= nse(QIOChannelWebsock *ioc, QIO_CHANNEL_WEBSOCK_GUID_LEN, &accept, errp) < 0) { - return -1; + qio_channel_websock_handshake_send_res_err( + ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_SERVER_ERR); + return; } =20 - response =3D g_strdup_printf(QIO_CHANNEL_WEBSOCK_HANDSHAKE_RESPONSE, a= ccept); - responselen =3D strlen(response); - buffer_reserve(&ioc->encoutput, responselen); - buffer_append(&ioc->encoutput, response, responselen); + qio_channel_websock_handshake_send_res( + ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_OK, date, accept); =20 + g_free(date); g_free(accept); - g_free(response); - - return 0; } =20 -static int qio_channel_websock_handshake_process(QIOChannelWebsock *ioc, - char *buffer, - Error **errp) +static void qio_channel_websock_handshake_process(QIOChannelWebsock *ioc, + char *buffer, + Error **errp) { QIOChannelWebsockHTTPHeader hdrs[32]; size_t nhdrs =3D G_N_ELEMENTS(hdrs); const char *protocols =3D NULL, *version =3D NULL, *key =3D NULL, *host =3D NULL, *connection =3D NULL, *upgrade =3D NULL; =20 - nhdrs =3D qio_channel_websock_extract_headers(buffer, hdrs, nhdrs, err= p); + nhdrs =3D qio_channel_websock_extract_headers(ioc, buffer, hdrs, nhdrs= , errp); if (!nhdrs) { - return -1; + return; } =20 protocols =3D qio_channel_websock_find_header( hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL); if (!protocols) { error_setg(errp, "Missing websocket protocol header data"); - return -1; + goto bad_request; } =20 version =3D qio_channel_websock_find_header( hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_VERSION); if (!version) { error_setg(errp, "Missing websocket version header data"); - return -1; + goto bad_request; } =20 key =3D qio_channel_websock_find_header( hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_KEY); if (!key) { error_setg(errp, "Missing websocket key header data"); - return -1; + goto bad_request; } =20 host =3D qio_channel_websock_find_header( hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_HOST); if (!host) { error_setg(errp, "Missing websocket host header data"); - return -1; + goto bad_request; } =20 connection =3D qio_channel_websock_find_header( hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION); if (!connection) { error_setg(errp, "Missing websocket connection header data"); - return -1; + goto bad_request; } =20 upgrade =3D qio_channel_websock_find_header( hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE); if (!upgrade) { error_setg(errp, "Missing websocket upgrade header data"); - return -1; + goto bad_request; } =20 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); - return -1; + goto bad_request; } =20 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); - return -1; + goto bad_request; } =20 if (strlen(key) !=3D 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); - return -1; + goto bad_request; } =20 if (!g_strrstr(connection, QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE)) { error_setg(errp, "No connection upgrade requested '%s'", connectio= n); - return -1; + goto bad_request; } =20 if (!g_str_equal(upgrade, QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET)) { error_setg(errp, "Incorrect upgrade method '%s'", upgrade); - return -1; + goto bad_request; } =20 - return qio_channel_websock_handshake_send_response(ioc, key, errp); + qio_channel_websock_handshake_send_res_ok(ioc, key, errp); + return; + + bad_request: + qio_channel_websock_handshake_send_res_err( + ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_BAD_REQUEST); } =20 static int qio_channel_websock_handshake_read(QIOChannelWebsock *ioc, @@ -393,20 +470,20 @@ static int qio_channel_websock_handshake_read(QIOChan= nelWebsock *ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_END); if (!handshake_end) { if (ioc->encinput.offset >=3D 4096) { + qio_channel_websock_handshake_send_res_err( + ioc, QIO_CHANNEL_WEBSOCK_HANDSHAKE_RES_TOO_LARGE); error_setg(errp, "End of headers not found in first 4096 bytes"); - return -1; + return 1; } else { return 0; } } *handshake_end =3D '\0'; =20 - if (qio_channel_websock_handshake_process(ioc, - (char *)ioc->encinput.buffer, - errp) < 0) { - return -1; - } + qio_channel_websock_handshake_process(ioc, + (char *)ioc->encinput.buffer, + errp); =20 buffer_advance(&ioc->encinput, handshake_end - (char *)ioc->encinput.buffer + @@ -438,8 +515,15 @@ static gboolean qio_channel_websock_handshake_send(QIO= Channel *ioc, =20 buffer_advance(&wioc->encoutput, ret); if (wioc->encoutput.offset =3D=3D 0) { - trace_qio_channel_websock_handshake_complete(ioc); - qio_task_complete(task); + if (wioc->io_err) { + trace_qio_channel_websock_handshake_fail(ioc); + qio_task_set_error(task, wioc->io_err); + wioc->io_err =3D NULL; + qio_task_complete(task); + } else { + trace_qio_channel_websock_handshake_complete(ioc); + qio_task_complete(task); + } return FALSE; } trace_qio_channel_websock_handshake_pending(ioc, G_IO_OUT); @@ -458,6 +542,11 @@ static gboolean qio_channel_websock_handshake_io(QIOCh= annel *ioc, =20 ret =3D qio_channel_websock_handshake_read(wioc, &err); if (ret < 0) { + /* + * We only take this path on a fatal I/O error reading from + * client connection, as most of the time we have an + * HTTP 4xx err response to send instead + */ trace_qio_channel_websock_handshake_fail(ioc); qio_task_set_error(task, err); qio_task_complete(task); @@ -469,6 +558,10 @@ static gboolean qio_channel_websock_handshake_io(QIOCh= annel *ioc, return TRUE; } =20 + if (err) { + error_propagate(&wioc->io_err, err); + } + trace_qio_channel_websock_handshake_reply(ioc); qio_channel_add_watch( wioc->master, --=20 2.13.5 From nobody Sat May 4 17:16:08 2024 Delivered-To: importer@patchew.org Received-SPF: temperror (zoho.com: Error in retrieving data from DNS) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=temperror (zoho.com: Error in retrieving data from DNS) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1507120052252947.4500440125535; Wed, 4 Oct 2017 05:27:32 -0700 (PDT) Received: from localhost ([::1]:34950 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzill-00040O-6r for importer@patchew.org; Wed, 04 Oct 2017 08:27:21 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55115) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzijs-0002iN-EK for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:25 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dzijr-0005IW-Ho for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:24 -0400 Received: from mx1.redhat.com ([209.132.183.28]:41935) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dzijr-0005Gk-9C for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:23 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 62DF72CE939; Wed, 4 Oct 2017 12:25:22 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 862405C891; Wed, 4 Oct 2017 12:25:21 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 62DF72CE939 Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=berrange@redhat.com From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Wed, 4 Oct 2017 13:25:06 +0100 Message-Id: <20171004122515.20627-3-berrange@redhat.com> In-Reply-To: <20171004122515.20627-1-berrange@redhat.com> References: <20171004122515.20627-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Wed, 04 Oct 2017 12:25:22 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v1 02/11] io: include full error message in websocket handshake trace X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_6 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" When the websocket handshake fails it is useful to log the real error message via the trace points for debugging purposes. Fixes bug: #1715186 Reviewed-by: Philippe Mathieu-Daud=C3=A9 Signed-off-by: Daniel P. Berrange --- io/channel-websock.c | 7 ++++--- io/trace-events | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/io/channel-websock.c b/io/channel-websock.c index f5fac5b422..6ddcec1549 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -507,7 +507,7 @@ static gboolean qio_channel_websock_handshake_send(QIOC= hannel *ioc, &err); =20 if (ret < 0) { - trace_qio_channel_websock_handshake_fail(ioc); + trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err= )); qio_task_set_error(task, err); qio_task_complete(task); return FALSE; @@ -516,7 +516,8 @@ static gboolean qio_channel_websock_handshake_send(QIOC= hannel *ioc, buffer_advance(&wioc->encoutput, ret); if (wioc->encoutput.offset =3D=3D 0) { if (wioc->io_err) { - trace_qio_channel_websock_handshake_fail(ioc); + trace_qio_channel_websock_handshake_fail( + ioc, error_get_pretty(wioc->io_err)); qio_task_set_error(task, wioc->io_err); wioc->io_err =3D NULL; qio_task_complete(task); @@ -547,7 +548,7 @@ static gboolean qio_channel_websock_handshake_io(QIOCha= nnel *ioc, * client connection, as most of the time we have an * HTTP 4xx err response to send instead */ - trace_qio_channel_websock_handshake_fail(ioc); + trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err= )); qio_task_set_error(task, err); qio_task_complete(task); return FALSE; diff --git a/io/trace-events b/io/trace-events index 3d233698d0..6459f71f5b 100644 --- a/io/trace-events +++ b/io/trace-events @@ -46,7 +46,7 @@ qio_channel_websock_new_server(void *ioc, void *master) "= Websock new client ioc=3D qio_channel_websock_handshake_start(void *ioc) "Websock handshake start io= c=3D%p" qio_channel_websock_handshake_pending(void *ioc, int status) "Websock hand= shake pending ioc=3D%p status=3D%d" qio_channel_websock_handshake_reply(void *ioc) "Websock handshake reply io= c=3D%p" -qio_channel_websock_handshake_fail(void *ioc) "Websock handshake fail ioc= =3D%p" +qio_channel_websock_handshake_fail(void *ioc, const char *msg) "Websock ha= ndshake fail ioc=3D%p err=3D%s" qio_channel_websock_handshake_complete(void *ioc) "Websock handshake compl= ete ioc=3D%p" =20 # io/channel-command.c --=20 2.13.5 From nobody Sat May 4 17:16:08 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 150712002631092.76090451337654; Wed, 4 Oct 2017 05:27:06 -0700 (PDT) Received: from localhost ([::1]:34948 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzilJ-0003eB-TX for importer@patchew.org; Wed, 04 Oct 2017 08:26:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55129) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dziju-0002jL-BI for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dzijt-0005M4-EK for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:26 -0400 Received: from mx1.redhat.com ([209.132.183.28]:56016) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dzijt-0005KI-2R for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:25 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 22B8A7F408; Wed, 4 Oct 2017 12:25:24 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id BC7845C548; Wed, 4 Oct 2017 12:25:22 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 22B8A7F408 Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=berrange@redhat.com From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Wed, 4 Oct 2017 13:25:07 +0100 Message-Id: <20171004122515.20627-4-berrange@redhat.com> In-Reply-To: <20171004122515.20627-1-berrange@redhat.com> References: <20171004122515.20627-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Wed, 04 Oct 2017 12:25:24 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v1 03/11] io: use case insensitive check for Connection & Upgrade websock headers X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" When checking the value of the Connection and Upgrade HTTP headers the websock RFC (6455) requires the comparison to be case insensitive. The Connection value should be an exact match not a substring. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange --- io/channel-websock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/io/channel-websock.c b/io/channel-websock.c index 6ddcec1549..2258557a21 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -431,12 +431,12 @@ static void qio_channel_websock_handshake_process(QIO= ChannelWebsock *ioc, goto bad_request; } =20 - if (!g_strrstr(connection, QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE)) { + if (strcasecmp(connection, QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE) != =3D 0) { error_setg(errp, "No connection upgrade requested '%s'", connectio= n); goto bad_request; } =20 - if (!g_str_equal(upgrade, QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET)) { + if (strcasecmp(upgrade, QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET) !=3D 0)= { error_setg(errp, "Incorrect upgrade method '%s'", upgrade); goto bad_request; } --=20 2.13.5 From nobody Sat May 4 17:16:08 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 15071201423901015.2345781025847; Wed, 4 Oct 2017 05:29:02 -0700 (PDT) Received: from localhost ([::1]:34957 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzinK-0005Oq-Ji for importer@patchew.org; Wed, 04 Oct 2017 08:28:58 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55146) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzijv-0002kO-Uo for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dziju-0005OA-N1 for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:27 -0400 Received: from mx1.redhat.com ([209.132.183.28]:46220) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dziju-0005Mx-DG for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:26 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6FF4690E4F; Wed, 4 Oct 2017 12:25:25 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7C8305C548; Wed, 4 Oct 2017 12:25:24 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 6FF4690E4F Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=berrange@redhat.com From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Wed, 4 Oct 2017 13:25:08 +0100 Message-Id: <20171004122515.20627-5-berrange@redhat.com> In-Reply-To: <20171004122515.20627-1-berrange@redhat.com> References: <20171004122515.20627-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Wed, 04 Oct 2017 12:25:25 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v1 04/11] ui: Always remove an old VNC channel watch before adding a new one X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Brandon Carpenter Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Brandon Carpenter Also set saved handle to zero when removing without adding a new watch. Signed-off-by: Brandon Carpenter Reviewed-by: Paolo Bonzini Reviewed-by: Daniel P. Berrange --- ui/vnc-auth-vencrypt.c | 3 +++ ui/vnc-ws.c | 6 ++++++ ui/vnc.c | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c index f0bec204b3..7833631275 100644 --- a/ui/vnc-auth-vencrypt.c +++ b/ui/vnc-auth-vencrypt.c @@ -75,6 +75,9 @@ static void vnc_tls_handshake_done(QIOTask *task, vnc_client_error(vs); error_free(err); } else { + if (vs->ioc_tag) { + g_source_remove(vs->ioc_tag); + } vs->ioc_tag =3D qio_channel_add_watch( vs->ioc, G_IO_IN | G_IO_OUT, vnc_client_io, vs, NULL); start_auth_vencrypt_subauth(vs); diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c index aeaafe2c21..6ccad22cef 100644 --- a/ui/vnc-ws.c +++ b/ui/vnc-ws.c @@ -37,6 +37,9 @@ static void vncws_tls_handshake_done(QIOTask *task, error_free(err); } else { VNC_DEBUG("TLS handshake complete, starting websocket handshake\n"= ); + if (vs->ioc_tag) { + g_source_remove(vs->ioc_tag); + } vs->ioc_tag =3D qio_channel_add_watch( QIO_CHANNEL(vs->ioc), G_IO_IN, vncws_handshake_io, vs, NULL); } @@ -97,6 +100,9 @@ static void vncws_handshake_done(QIOTask *task, } else { VNC_DEBUG("Websock handshake complete, starting VNC protocol\n"); vnc_start_protocol(vs); + if (vs->ioc_tag) { + g_source_remove(vs->ioc_tag); + } vs->ioc_tag =3D qio_channel_add_watch( vs->ioc, G_IO_IN, vnc_client_io, vs, NULL); } diff --git a/ui/vnc.c b/ui/vnc.c index af810f0547..9f8d5a1b1f 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1122,6 +1122,7 @@ static void vnc_disconnect_start(VncState *vs) vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED); if (vs->ioc_tag) { g_source_remove(vs->ioc_tag); + vs->ioc_tag =3D 0; } qio_channel_close(vs->ioc, NULL); vs->disconnecting =3D TRUE; @@ -2934,6 +2935,9 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSoc= ket *sioc, VNC_DEBUG("New client on socket %p\n", vs->sioc); update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE); qio_channel_set_blocking(vs->ioc, false, NULL); + if (vs->ioc_tag) { + g_source_remove(vs->ioc_tag); + } if (websocket) { vs->websocket =3D 1; if (vd->tlscreds) { --=20 2.13.5 From nobody Sat May 4 17:16:08 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1507120199126458.70311519375434; Wed, 4 Oct 2017 05:29:59 -0700 (PDT) Received: from localhost ([::1]:34959 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzioD-00067J-9R for importer@patchew.org; Wed, 04 Oct 2017 08:29:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55172) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzijx-0002li-Lu for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dzijw-0005R0-1X for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:29 -0400 Received: from mx1.redhat.com ([209.132.183.28]:18403) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dzijv-0005PM-OS for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:27 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id DAA3890E65; Wed, 4 Oct 2017 12:25:26 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id AFFB25C1A1; Wed, 4 Oct 2017 12:25:25 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com DAA3890E65 Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=berrange@redhat.com From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Wed, 4 Oct 2017 13:25:09 +0100 Message-Id: <20171004122515.20627-6-berrange@redhat.com> In-Reply-To: <20171004122515.20627-1-berrange@redhat.com> References: <20171004122515.20627-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Wed, 04 Oct 2017 12:25:27 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v1 05/11] io: Small updates in preparation for websocket changes X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Brandon Carpenter Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Brandon Carpenter Gets rid of unnecessary bit shifting and performs proper EOF checking to avoid a large number of repeated calls to recvmsg() when a client abruptly terminates a connection (bug fix). Signed-off-by: Brandon Carpenter Signed-off-by: Daniel P. Berrange --- io/channel-websock.c | 64 ++++++++++++++++--------------------------------= ---- 1 file changed, 19 insertions(+), 45 deletions(-) diff --git a/io/channel-websock.c b/io/channel-websock.c index 2258557a21..4e5afb2e95 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -110,13 +110,11 @@ /* Magic 7-bit length to indicate use of 64-bit payload length */ #define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT 127 =20 -/* Bitmasks & shifts for accessing header fields */ +/* Bitmasks for accessing header fields */ #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN 0x80 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE 0x0f #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK 0x80 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN 0x7f -#define QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_FIN 7 -#define QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_HAS_MASK 7 =20 typedef struct QIOChannelWebsockHeader QIOChannelWebsockHeader; =20 @@ -586,7 +584,7 @@ static void qio_channel_websock_encode(QIOChannelWebsoc= k *ioc) return; } =20 - header.ws.b0 =3D (1 << QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_FIN) | + header.ws.b0 =3D QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN | (QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE); if (ioc->rawoutput.offset < @@ -613,8 +611,8 @@ static void qio_channel_websock_encode(QIOChannelWebsoc= k *ioc) } =20 =20 -static ssize_t qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - Error **errp) +static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, + Error **errp) { unsigned char opcode, fin, has_mask; size_t header_size; @@ -633,11 +631,9 @@ static ssize_t qio_channel_websock_decode_header(QIOCh= annelWebsock *ioc, return QIO_CHANNEL_ERR_BLOCK; } =20 - fin =3D (header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN) >> - QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_FIN; + fin =3D header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN; opcode =3D header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE; - has_mask =3D (header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK) = >> - QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_HAS_MASK; + has_mask =3D header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK; payload_len =3D header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_= LEN; =20 if (opcode =3D=3D QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) { @@ -655,7 +651,7 @@ static ssize_t qio_channel_websock_decode_header(QIOCha= nnelWebsock *ioc, return -1; } if (!has_mask) { - error_setg(errp, "websocket frames must be masked"); + error_setg(errp, "client websocket frames must be masked"); return -1; } if (opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { @@ -687,8 +683,8 @@ static ssize_t qio_channel_websock_decode_header(QIOCha= nnelWebsock *ioc, } =20 =20 -static ssize_t qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - Error **errp) +static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, + Error **errp) { size_t i; size_t payload_len; @@ -729,7 +725,7 @@ static ssize_t qio_channel_websock_decode_payload(QIOCh= annelWebsock *ioc, buffer_reserve(&ioc->rawinput, payload_len); buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); buffer_advance(&ioc->encinput, payload_len); - return payload_len; + return 0; } =20 =20 @@ -809,8 +805,8 @@ static ssize_t qio_channel_websock_read_wire(QIOChannel= Websock *ioc, if (ret < 0) { return ret; } - if (ret =3D=3D 0 && - ioc->encinput.offset =3D=3D 0) { + if (ret =3D=3D 0 && ioc->encinput.offset =3D=3D 0) { + ioc->io_eof =3D TRUE; return 0; } ioc->encinput.offset +=3D ret; @@ -822,10 +818,6 @@ static ssize_t qio_channel_websock_read_wire(QIOChanne= lWebsock *ioc, if (ret < 0) { return ret; } - if (ret =3D=3D 0) { - ioc->io_eof =3D TRUE; - break; - } } =20 ret =3D qio_channel_websock_decode_payload(ioc, errp); @@ -1090,14 +1082,12 @@ struct QIOChannelWebsockSource { }; =20 static gboolean -qio_channel_websock_source_prepare(GSource *source, - gint *timeout) +qio_channel_websock_source_check(GSource *source) { QIOChannelWebsockSource *wsource =3D (QIOChannelWebsockSource *)source; GIOCondition cond =3D 0; - *timeout =3D -1; =20 - if (wsource->wioc->rawinput.offset) { + if (wsource->wioc->rawinput.offset || wsource->wioc->io_eof) { cond |=3D G_IO_IN; } if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { @@ -1108,19 +1098,11 @@ qio_channel_websock_source_prepare(GSource *source, } =20 static gboolean -qio_channel_websock_source_check(GSource *source) +qio_channel_websock_source_prepare(GSource *source, + gint *timeout) { - QIOChannelWebsockSource *wsource =3D (QIOChannelWebsockSource *)source; - GIOCondition cond =3D 0; - - if (wsource->wioc->rawinput.offset) { - cond |=3D G_IO_IN; - } - if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { - cond |=3D G_IO_OUT; - } - - return cond & wsource->condition; + *timeout =3D -1; + return qio_channel_websock_source_check(source); } =20 static gboolean @@ -1130,17 +1112,9 @@ qio_channel_websock_source_dispatch(GSource *source, { QIOChannelFunc func =3D (QIOChannelFunc)callback; QIOChannelWebsockSource *wsource =3D (QIOChannelWebsockSource *)source; - GIOCondition cond =3D 0; - - if (wsource->wioc->rawinput.offset) { - cond |=3D G_IO_IN; - } - if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { - cond |=3D G_IO_OUT; - } =20 return (*func)(QIO_CHANNEL(wsource->wioc), - (cond & wsource->condition), + qio_channel_websock_source_check(source), user_data); } =20 --=20 2.13.5 From nobody Sat May 4 17:16:08 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1507120304208602.8737617763583; Wed, 4 Oct 2017 05:31:44 -0700 (PDT) Received: from localhost ([::1]:34969 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzipx-0007Y4-8G for importer@patchew.org; Wed, 04 Oct 2017 08:31:41 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55195) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzik1-0002p4-24 for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:34 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dzijx-0005T7-NZ for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:33 -0400 Received: from mx1.redhat.com ([209.132.183.28]:43396) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dzijx-0005S0-6R for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:29 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 40AB25F922; Wed, 4 Oct 2017 12:25:28 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 344845C1A1; Wed, 4 Oct 2017 12:25:27 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 40AB25F922 Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=berrange@redhat.com From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Wed, 4 Oct 2017 13:25:10 +0100 Message-Id: <20171004122515.20627-7-berrange@redhat.com> In-Reply-To: <20171004122515.20627-1-berrange@redhat.com> References: <20171004122515.20627-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.28]); Wed, 04 Oct 2017 12:25:28 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v1 06/11] io: Add support for fragmented websocket binary frames X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Brandon Carpenter Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Brandon Carpenter Allows fragmented binary frames by saving the previous opcode. Handles the case where an intermediary (i.e., web proxy) fragments frames originally sent unfragmented by the client. Signed-off-by: Brandon Carpenter Signed-off-by: Daniel P. Berrange --- include/io/channel-websock.h | 1 + io/channel-websock.c | 26 ++++++++++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/include/io/channel-websock.h b/include/io/channel-websock.h index 3c9ff84727..7c896557c5 100644 --- a/include/io/channel-websock.h +++ b/include/io/channel-websock.h @@ -65,6 +65,7 @@ struct QIOChannelWebsock { guint io_tag; Error *io_err; gboolean io_eof; + uint8_t opcode; }; =20 /** diff --git a/io/channel-websock.c b/io/channel-websock.c index 4e5afb2e95..909d6367f0 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -636,28 +636,38 @@ static int qio_channel_websock_decode_header(QIOChann= elWebsock *ioc, has_mask =3D header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK; payload_len =3D header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_= LEN; =20 + /* Save or restore opcode. */ + if (opcode) { + ioc->opcode =3D opcode; + } else { + opcode =3D ioc->opcode; + } + if (opcode =3D=3D QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) { /* disconnect */ return 0; } =20 /* Websocket frame sanity check: - * * Websocket fragmentation is not supported. - * * All websockets frames sent by a client have to be masked. + * * Fragmentation is only supported for binary frames. + * * All frames sent by a client MUST be masked. * * Only binary encoding is supported. */ if (!fin) { - error_setg(errp, "websocket fragmentation is not supported"); - return -1; + if (opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { + error_setg(errp, "only binary websocket frames may be fragment= ed"); + return -1; + } + } else { + if (opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { + error_setg(errp, "only binary websocket frames are supported"); + return -1; + } } if (!has_mask) { error_setg(errp, "client websocket frames must be masked"); return -1; } - if (opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { - error_setg(errp, "only binary websocket frames are supported"); - return -1; - } =20 if (payload_len < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT) { ioc->payload_remain =3D payload_len; --=20 2.13.5 From nobody Sat May 4 17:16:08 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1507120480992252.18091746359403; Wed, 4 Oct 2017 05:34:40 -0700 (PDT) Received: from localhost ([::1]:34984 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzisi-00019N-Qi for importer@patchew.org; Wed, 04 Oct 2017 08:34:32 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55196) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzik1-0002p5-2D for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dzijz-0005VS-3f for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:32 -0400 Received: from mx1.redhat.com ([209.132.183.28]:44500) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dzijy-0005U1-QW for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:31 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D7135C04B92C; Wed, 4 Oct 2017 12:25:29 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id A31B75C886; Wed, 4 Oct 2017 12:25:28 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com D7135C04B92C Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=berrange@redhat.com From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Wed, 4 Oct 2017 13:25:11 +0100 Message-Id: <20171004122515.20627-8-berrange@redhat.com> In-Reply-To: <20171004122515.20627-1-berrange@redhat.com> References: <20171004122515.20627-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Wed, 04 Oct 2017 12:25:30 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v1 07/11] io: Allow empty websocket payload X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Brandon Carpenter Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Brandon Carpenter Some browsers send pings/pongs with no payload, so allow empty payloads instead of closing the connection. Signed-off-by: Brandon Carpenter Signed-off-by: Daniel P. Berrange --- io/channel-websock.c | 62 +++++++++++++++++++++++++-----------------------= ---- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/io/channel-websock.c b/io/channel-websock.c index 909d6367f0..b19b5d96da 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -697,44 +697,42 @@ static int qio_channel_websock_decode_payload(QIOChan= nelWebsock *ioc, Error **errp) { size_t i; - size_t payload_len; + size_t payload_len =3D 0; uint32_t *payload32; =20 - if (!ioc->payload_remain) { - error_setg(errp, - "Decoding payload but no bytes of payload remain"); - return -1; - } - - /* If we aren't at the end of the payload, then drop - * off the last bytes, so we're always multiple of 4 - * for purpose of unmasking, except at end of payload - */ - if (ioc->encinput.offset < ioc->payload_remain) { - payload_len =3D ioc->encinput.offset - (ioc->encinput.offset % 4); - } else { - payload_len =3D ioc->payload_remain; - } - if (payload_len =3D=3D 0) { - return QIO_CHANNEL_ERR_BLOCK; - } + if (ioc->payload_remain) { + /* If we aren't at the end of the payload, then drop + * off the last bytes, so we're always multiple of 4 + * for purpose of unmasking, except at end of payload + */ + if (ioc->encinput.offset < ioc->payload_remain) { + payload_len =3D ioc->encinput.offset - (ioc->encinput.offset %= 4); + } else { + payload_len =3D ioc->payload_remain; + } + if (payload_len =3D=3D 0) { + return QIO_CHANNEL_ERR_BLOCK; + } =20 - ioc->payload_remain -=3D payload_len; + ioc->payload_remain -=3D payload_len; =20 - /* unmask frame */ - /* process 1 frame (32 bit op) */ - payload32 =3D (uint32_t *)ioc->encinput.buffer; - for (i =3D 0; i < payload_len / 4; i++) { - payload32[i] ^=3D ioc->mask.u; - } - /* process the remaining bytes (if any) */ - for (i *=3D 4; i < payload_len; i++) { - ioc->encinput.buffer[i] ^=3D ioc->mask.c[i % 4]; + /* unmask frame */ + /* process 1 frame (32 bit op) */ + payload32 =3D (uint32_t *)ioc->encinput.buffer; + for (i =3D 0; i < payload_len / 4; i++) { + payload32[i] ^=3D ioc->mask.u; + } + /* process the remaining bytes (if any) */ + for (i *=3D 4; i < payload_len; i++) { + ioc->encinput.buffer[i] ^=3D ioc->mask.c[i % 4]; + } } =20 - buffer_reserve(&ioc->rawinput, payload_len); - buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); - buffer_advance(&ioc->encinput, payload_len); + if (payload_len) { + buffer_reserve(&ioc->rawinput, payload_len); + buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); + buffer_advance(&ioc->encinput, payload_len); + } return 0; } =20 --=20 2.13.5 From nobody Sat May 4 17:16:08 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1507120372052816.4075292047007; Wed, 4 Oct 2017 05:32:52 -0700 (PDT) Received: from localhost ([::1]:34974 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dziqy-0008Ih-4j for importer@patchew.org; Wed, 04 Oct 2017 08:32:44 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55210) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzik1-0002pT-OK for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:34 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dzik0-0005X5-K7 for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:33 -0400 Received: from mx1.redhat.com ([209.132.183.28]:44600) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dzik0-0005W0-BP for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:32 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 63FE4C04AC50; Wed, 4 Oct 2017 12:25:31 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3ADDF5C1A1; Wed, 4 Oct 2017 12:25:30 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 63FE4C04AC50 Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=berrange@redhat.com From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Wed, 4 Oct 2017 13:25:12 +0100 Message-Id: <20171004122515.20627-9-berrange@redhat.com> In-Reply-To: <20171004122515.20627-1-berrange@redhat.com> References: <20171004122515.20627-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Wed, 04 Oct 2017 12:25:31 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v1 08/11] io: Ignore websocket PING and PONG frames X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Brandon Carpenter Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Brandon Carpenter Keep pings and gratuitous pongs generated by web browsers from killing websocket connections. Signed-off-by: Brandon Carpenter Signed-off-by: Daniel P. Berrange --- io/channel-websock.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/io/channel-websock.c b/io/channel-websock.c index b19b5d96da..bfe4008d83 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -115,6 +115,7 @@ #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE 0x0f #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK 0x80 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN 0x7f +#define QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK 0x8 =20 typedef struct QIOChannelWebsockHeader QIOChannelWebsockHeader; =20 @@ -659,8 +660,11 @@ static int qio_channel_websock_decode_header(QIOChanne= lWebsock *ioc, return -1; } } else { - if (opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { - error_setg(errp, "only binary websocket frames are supported"); + if (opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME && + opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_PING && + opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_PONG) { + error_setg(errp, "unsupported opcode: %#04x; only binary, ping= , " + "and pong websocket frames are supported", op= code); return -1; } } @@ -673,6 +677,9 @@ static int qio_channel_websock_decode_header(QIOChannel= Websock *ioc, ioc->payload_remain =3D payload_len; header_size =3D QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT; ioc->mask =3D header->u.m; + } else if (opcode & QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK) { + error_setg(errp, "websocket control frame is too large"); + return -1; } else if (payload_len =3D=3D QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16= _BIT && ioc->encinput.offset >=3D QIO_CHANNEL_WEBSOCK_HEADER_LEN_16= _BIT) { ioc->payload_remain =3D be16_to_cpu(header->u.s16.l16); @@ -728,9 +735,15 @@ static int qio_channel_websock_decode_payload(QIOChann= elWebsock *ioc, } } =20 + /* Drop the payload of ping/pong packets */ + if (ioc->opcode =3D=3D QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { + if (payload_len) { + buffer_reserve(&ioc->rawinput, payload_len); + buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_le= n); + } + } + if (payload_len) { - buffer_reserve(&ioc->rawinput, payload_len); - buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); buffer_advance(&ioc->encinput, payload_len); } return 0; --=20 2.13.5 From nobody Sat May 4 17:16:08 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1507120415542829.6183339457212; Wed, 4 Oct 2017 05:33:35 -0700 (PDT) Received: from localhost ([::1]:34977 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzirj-0000RK-N8 for importer@patchew.org; Wed, 04 Oct 2017 08:33:31 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55221) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzik3-0002qa-CI for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dzik2-0005Ym-1y for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:35 -0400 Received: from mx1.redhat.com ([209.132.183.28]:39406) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dzik1-0005Y5-P6 for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:33 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E137C267DB; Wed, 4 Oct 2017 12:25:32 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id BD8525C886; Wed, 4 Oct 2017 12:25:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com E137C267DB Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=berrange@redhat.com From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Wed, 4 Oct 2017 13:25:13 +0100 Message-Id: <20171004122515.20627-10-berrange@redhat.com> In-Reply-To: <20171004122515.20627-1-berrange@redhat.com> References: <20171004122515.20627-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Wed, 04 Oct 2017 12:25:33 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v1 09/11] io: Reply to ping frames X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Brandon Carpenter Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Brandon Carpenter Add an immediate ping reply (pong) to the outgoing stream when a ping is received. Unsolicited pongs are ignored. Signed-off-by: Brandon Carpenter Signed-off-by: Daniel P. Berrange --- include/io/channel-websock.h | 1 + io/channel-websock.c | 66 +++++++++++++++++++++++++++++-----------= ---- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/include/io/channel-websock.h b/include/io/channel-websock.h index 7c896557c5..ff32d8651b 100644 --- a/include/io/channel-websock.h +++ b/include/io/channel-websock.h @@ -60,6 +60,7 @@ struct QIOChannelWebsock { Buffer encoutput; Buffer rawinput; Buffer rawoutput; + Buffer ping_reply; size_t payload_remain; QIOChannelWebsockMask mask; guint io_tag; diff --git a/io/channel-websock.c b/io/channel-websock.c index bfe4008d83..b6fc0c9b8e 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -573,7 +573,8 @@ static gboolean qio_channel_websock_handshake_io(QIOCha= nnel *ioc, } =20 =20 -static void qio_channel_websock_encode(QIOChannelWebsock *ioc) +static void qio_channel_websock_encode_buffer(Buffer *output, + uint8_t opcode, Buffer *buff= er) { size_t header_size; union { @@ -581,33 +582,37 @@ static void qio_channel_websock_encode(QIOChannelWebs= ock *ioc) QIOChannelWebsockHeader ws; } header; =20 - if (!ioc->rawoutput.offset) { - return; - } - header.ws.b0 =3D QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN | - (QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME & - QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE); - if (ioc->rawoutput.offset < - QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_7_BIT) { - header.ws.b1 =3D (uint8_t)ioc->rawoutput.offset; + (opcode & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE); + if (buffer->offset < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_7_BIT) { + header.ws.b1 =3D (uint8_t)buffer->offset; header_size =3D QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT; - } else if (ioc->rawoutput.offset < + } else if (buffer->offset < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_16_BIT) { header.ws.b1 =3D QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT; - header.ws.u.s16.l16 =3D cpu_to_be16((uint16_t)ioc->rawoutput.offse= t); + header.ws.u.s16.l16 =3D cpu_to_be16((uint16_t)buffer->offset); header_size =3D QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT; } else { header.ws.b1 =3D QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT; - header.ws.u.s64.l64 =3D cpu_to_be64(ioc->rawoutput.offset); + header.ws.u.s64.l64 =3D cpu_to_be64(buffer->offset); header_size =3D QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT; } header_size -=3D QIO_CHANNEL_WEBSOCK_HEADER_LEN_MASK; =20 - buffer_reserve(&ioc->encoutput, header_size + ioc->rawoutput.offset); - buffer_append(&ioc->encoutput, header.buf, header_size); - buffer_append(&ioc->encoutput, ioc->rawoutput.buffer, - ioc->rawoutput.offset); + buffer_reserve(output, header_size + buffer->offset); + buffer_append(output, header.buf, header_size); + buffer_append(output, buffer->buffer, buffer->offset); +} + + +static void qio_channel_websock_encode(QIOChannelWebsock *ioc) +{ + if (!ioc->rawoutput.offset) { + return; + } + qio_channel_websock_encode_buffer( + &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME, + &ioc->rawoutput); buffer_reset(&ioc->rawoutput); } =20 @@ -652,7 +657,7 @@ static int qio_channel_websock_decode_header(QIOChannel= Websock *ioc, /* Websocket frame sanity check: * * Fragmentation is only supported for binary frames. * * All frames sent by a client MUST be masked. - * * Only binary encoding is supported. + * * Only binary and ping/pong encoding is supported. */ if (!fin) { if (opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { @@ -713,6 +718,11 @@ static int qio_channel_websock_decode_payload(QIOChann= elWebsock *ioc, * for purpose of unmasking, except at end of payload */ if (ioc->encinput.offset < ioc->payload_remain) { + /* Wait for the entire payload before processing control frames + * because the payload will most likely be echoed back. */ + if (ioc->opcode & QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK) { + return QIO_CHANNEL_ERR_BLOCK; + } payload_len =3D ioc->encinput.offset - (ioc->encinput.offset %= 4); } else { payload_len =3D ioc->payload_remain; @@ -735,13 +745,18 @@ static int qio_channel_websock_decode_payload(QIOChan= nelWebsock *ioc, } } =20 - /* Drop the payload of ping/pong packets */ if (ioc->opcode =3D=3D QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { if (payload_len) { + /* binary frames are passed on */ buffer_reserve(&ioc->rawinput, payload_len); buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_le= n); } - } + } else if (ioc->opcode =3D=3D QIO_CHANNEL_WEBSOCK_OPCODE_PING) { + /* ping frames produce an immediate reply */ + buffer_reset(&ioc->ping_reply); + qio_channel_websock_encode_buffer( + &ioc->ping_reply, QIO_CHANNEL_WEBSOCK_OPCODE_PONG, &ioc->encin= put); + } /* pong frames are ignored */ =20 if (payload_len) { buffer_advance(&ioc->encinput, payload_len); @@ -799,6 +814,7 @@ static void qio_channel_websock_finalize(Object *obj) buffer_free(&ioc->encoutput); buffer_free(&ioc->rawinput); buffer_free(&ioc->rawoutput); + buffer_free(&ioc->ping_reply); object_unref(OBJECT(ioc->master)); if (ioc->io_tag) { g_source_remove(ioc->io_tag); @@ -855,7 +871,13 @@ static ssize_t qio_channel_websock_write_wire(QIOChann= elWebsock *ioc, { ssize_t ret; ssize_t done =3D 0; - qio_channel_websock_encode(ioc); + + /* ping replies take priority over binary data */ + if (!ioc->ping_reply.offset) { + qio_channel_websock_encode(ioc); + } else if (!ioc->encoutput.offset) { + buffer_move_empty(&ioc->encoutput, &ioc->ping_reply); + } =20 while (ioc->encoutput.offset > 0) { ret =3D qio_channel_write(ioc->master, @@ -930,7 +952,7 @@ static void qio_channel_websock_set_watch(QIOChannelWeb= sock *ioc) return; } =20 - if (ioc->encoutput.offset) { + if (ioc->encoutput.offset || ioc->ping_reply.offset) { cond |=3D G_IO_OUT; } if (ioc->encinput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER && --=20 2.13.5 From nobody Sat May 4 17:16:08 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1507120520972988.0173737333436; Wed, 4 Oct 2017 05:35:20 -0700 (PDT) Received: from localhost ([::1]:34985 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzitU-0001fe-8v for importer@patchew.org; Wed, 04 Oct 2017 08:35:20 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55251) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzik7-0002uc-TG for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dzik3-0005cn-Nb for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:39 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57222) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dzik3-0005ap-DP for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:35 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5AC6750EE4; Wed, 4 Oct 2017 12:25:34 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3E0CB5C548; Wed, 4 Oct 2017 12:25:33 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 5AC6750EE4 Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=berrange@redhat.com From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Wed, 4 Oct 2017 13:25:14 +0100 Message-Id: <20171004122515.20627-11-berrange@redhat.com> In-Reply-To: <20171004122515.20627-1-berrange@redhat.com> References: <20171004122515.20627-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Wed, 04 Oct 2017 12:25:34 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v1 10/11] io: Attempt to send websocket close messages to client X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Brandon Carpenter Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Brandon Carpenter Make a best effort attempt to close websocket connections according to the RFC. Sends the close message, as room permits in the socket buffer, and immediately closes the socket. Signed-off-by: Brandon Carpenter Signed-off-by: Daniel P. Berrange --- io/channel-websock.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++= +--- 1 file changed, 65 insertions(+), 3 deletions(-) diff --git a/io/channel-websock.c b/io/channel-websock.c index b6fc0c9b8e..3195eb2eb8 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -188,6 +188,15 @@ static void qio_channel_websock_handshake_send_res_err= (QIOChannelWebsock *ioc, g_free(date); } =20 +enum { + QIO_CHANNEL_WEBSOCK_STATUS_NORMAL =3D 1000, + QIO_CHANNEL_WEBSOCK_STATUS_PROTOCOL_ERR =3D 1002, + QIO_CHANNEL_WEBSOCK_STATUS_INVALID_DATA =3D 1003, + QIO_CHANNEL_WEBSOCK_STATUS_POLICY =3D 1008, + QIO_CHANNEL_WEBSOCK_STATUS_TOO_LARGE =3D 1009, + QIO_CHANNEL_WEBSOCK_STATUS_SERVER_ERR =3D 1011, +}; + static size_t qio_channel_websock_extract_headers(QIOChannelWebsock *ioc, char *buffer, @@ -617,6 +626,27 @@ static void qio_channel_websock_encode(QIOChannelWebso= ck *ioc) } =20 =20 +static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *, Error *= *); + + +static void qio_channel_websock_write_close(QIOChannelWebsock *ioc, + uint16_t code, const char *rea= son) +{ + buffer_reserve(&ioc->rawoutput, 2 + (reason ? strlen(reason) : 0)); + *(uint16_t *)(ioc->rawoutput.buffer + ioc->rawoutput.offset) =3D + cpu_to_be16(code); + ioc->rawoutput.offset +=3D 2; + if (reason) { + buffer_append(&ioc->rawoutput, reason, strlen(reason)); + } + qio_channel_websock_encode_buffer( + &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, &ioc->rawoutput= ); + buffer_reset(&ioc->rawoutput); + qio_channel_websock_write_wire(ioc, NULL); + qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); +} + + static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, Error **errp) { @@ -630,6 +660,9 @@ static int qio_channel_websock_decode_header(QIOChannel= Websock *ioc, error_setg(errp, "Decoding header but %zu bytes of payload remain", ioc->payload_remain); + qio_channel_websock_write_close( + ioc, QIO_CHANNEL_WEBSOCK_STATUS_SERVER_ERR, + "internal server error"); return -1; } if (ioc->encinput.offset < QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT) { @@ -662,19 +695,29 @@ static int qio_channel_websock_decode_header(QIOChann= elWebsock *ioc, if (!fin) { if (opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { error_setg(errp, "only binary websocket frames may be fragment= ed"); + qio_channel_websock_write_close( + ioc, QIO_CHANNEL_WEBSOCK_STATUS_POLICY , + "only binary frames may be fragmented"); return -1; } } else { if (opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME && + opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE && opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_PING && opcode !=3D QIO_CHANNEL_WEBSOCK_OPCODE_PONG) { - error_setg(errp, "unsupported opcode: %#04x; only binary, ping= , " - "and pong websocket frames are supported", op= code); + error_setg(errp, "unsupported opcode: %#04x; only binary, clos= e, " + "ping, and pong websocket frames are supported", op= code); + qio_channel_websock_write_close( + ioc, QIO_CHANNEL_WEBSOCK_STATUS_INVALID_DATA , + "only binary, close, ping, and pong frames are supported"); return -1; } } if (!has_mask) { error_setg(errp, "client websocket frames must be masked"); + qio_channel_websock_write_close( + ioc, QIO_CHANNEL_WEBSOCK_STATUS_PROTOCOL_ERR, + "client frames must be masked"); return -1; } =20 @@ -684,6 +727,9 @@ static int qio_channel_websock_decode_header(QIOChannel= Websock *ioc, ioc->mask =3D header->u.m; } else if (opcode & QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK) { error_setg(errp, "websocket control frame is too large"); + qio_channel_websock_write_close( + ioc, QIO_CHANNEL_WEBSOCK_STATUS_PROTOCOL_ERR, + "control frame is too large"); return -1; } else if (payload_len =3D=3D QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16= _BIT && ioc->encinput.offset >=3D QIO_CHANNEL_WEBSOCK_HEADER_LEN_16= _BIT) { @@ -701,7 +747,7 @@ static int qio_channel_websock_decode_header(QIOChannel= Websock *ioc, } =20 buffer_advance(&ioc->encinput, header_size); - return 1; + return 0; } =20 =20 @@ -751,6 +797,22 @@ static int qio_channel_websock_decode_payload(QIOChann= elWebsock *ioc, buffer_reserve(&ioc->rawinput, payload_len); buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_le= n); } + } else if (ioc->opcode =3D=3D QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) { + /* close frames are echoed back */ + error_setg(errp, "websocket closed by peer"); + if (payload_len) { + /* echo client status */ + qio_channel_websock_encode_buffer( + &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, + &ioc->encinput); + qio_channel_websock_write_wire(ioc, NULL); + qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, N= ULL); + } else { + /* send our own status */ + qio_channel_websock_write_close( + ioc, QIO_CHANNEL_WEBSOCK_STATUS_NORMAL, "peer requested cl= ose"); + } + return -1; } else if (ioc->opcode =3D=3D QIO_CHANNEL_WEBSOCK_OPCODE_PING) { /* ping frames produce an immediate reply */ buffer_reset(&ioc->ping_reply); --=20 2.13.5 From nobody Sat May 4 17:16:08 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1507120640568860.0045272252412; Wed, 4 Oct 2017 05:37:20 -0700 (PDT) Received: from localhost ([::1]:35003 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzivC-0002sy-Po for importer@patchew.org; Wed, 04 Oct 2017 08:37:06 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55260) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dzikB-0002xq-Cp for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dzik4-0005f3-UR for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:43 -0400 Received: from mx1.redhat.com ([209.132.183.28]:46992) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dzik4-0005dQ-Kv for qemu-devel@nongnu.org; Wed, 04 Oct 2017 08:25:36 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B053290E44; Wed, 4 Oct 2017 12:25:35 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id A852C5C1A1; Wed, 4 Oct 2017 12:25:34 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com B053290E44 Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=berrange@redhat.com From: "Daniel P. Berrange" To: qemu-devel@nongnu.org Date: Wed, 4 Oct 2017 13:25:15 +0100 Message-Id: <20171004122515.20627-12-berrange@redhat.com> In-Reply-To: <20171004122515.20627-1-berrange@redhat.com> References: <20171004122515.20627-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Wed, 04 Oct 2017 12:25:35 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL v1 11/11] io: add trace events for websockets frame handling X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" It is useful to trace websockets frame encoding/decoding when debugging problems. Reviewed-by: Stefan Hajnoczi Signed-off-by: Daniel P. Berrange --- io/channel-websock.c | 23 ++++++++++++++++++----- io/trace-events | 5 +++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/io/channel-websock.c b/io/channel-websock.c index 3195eb2eb8..d1d471f86e 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -582,7 +582,8 @@ static gboolean qio_channel_websock_handshake_io(QIOCha= nnel *ioc, } =20 =20 -static void qio_channel_websock_encode_buffer(Buffer *output, +static void qio_channel_websock_encode_buffer(QIOChannelWebsock *ioc, + Buffer *output, uint8_t opcode, Buffer *buff= er) { size_t header_size; @@ -608,6 +609,7 @@ static void qio_channel_websock_encode_buffer(Buffer *o= utput, } header_size -=3D QIO_CHANNEL_WEBSOCK_HEADER_LEN_MASK; =20 + trace_qio_channel_websock_encode(ioc, opcode, header_size, buffer->off= set); buffer_reserve(output, header_size + buffer->offset); buffer_append(output, header.buf, header_size); buffer_append(output, buffer->buffer, buffer->offset); @@ -620,7 +622,7 @@ static void qio_channel_websock_encode(QIOChannelWebsoc= k *ioc) return; } qio_channel_websock_encode_buffer( - &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME, + ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME, &ioc->rawoutput); buffer_reset(&ioc->rawoutput); } @@ -640,7 +642,8 @@ static void qio_channel_websock_write_close(QIOChannelW= ebsock *ioc, buffer_append(&ioc->rawoutput, reason, strlen(reason)); } qio_channel_websock_encode_buffer( - &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, &ioc->rawoutput= ); + ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, + &ioc->rawoutput); buffer_reset(&ioc->rawoutput); qio_channel_websock_write_wire(ioc, NULL); qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); @@ -682,6 +685,9 @@ static int qio_channel_websock_decode_header(QIOChannel= Websock *ioc, opcode =3D ioc->opcode; } =20 + trace_qio_channel_websock_header_partial_decode(ioc, payload_len, + fin, opcode, (int)has_= mask); + if (opcode =3D=3D QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) { /* disconnect */ return 0; @@ -746,6 +752,8 @@ static int qio_channel_websock_decode_header(QIOChannel= Websock *ioc, return QIO_CHANNEL_ERR_BLOCK; } =20 + trace_qio_channel_websock_header_full_decode( + ioc, header_size, ioc->payload_remain, ioc->mask.u); buffer_advance(&ioc->encinput, header_size); return 0; } @@ -791,6 +799,9 @@ static int qio_channel_websock_decode_payload(QIOChanne= lWebsock *ioc, } } =20 + trace_qio_channel_websock_payload_decode( + ioc, ioc->opcode, ioc->payload_remain); + if (ioc->opcode =3D=3D QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { if (payload_len) { /* binary frames are passed on */ @@ -803,7 +814,7 @@ static int qio_channel_websock_decode_payload(QIOChanne= lWebsock *ioc, if (payload_len) { /* echo client status */ qio_channel_websock_encode_buffer( - &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, + ioc, &ioc->encoutput, QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE, &ioc->encinput); qio_channel_websock_write_wire(ioc, NULL); qio_channel_shutdown(ioc->master, QIO_CHANNEL_SHUTDOWN_BOTH, N= ULL); @@ -817,7 +828,8 @@ static int qio_channel_websock_decode_payload(QIOChanne= lWebsock *ioc, /* ping frames produce an immediate reply */ buffer_reset(&ioc->ping_reply); qio_channel_websock_encode_buffer( - &ioc->ping_reply, QIO_CHANNEL_WEBSOCK_OPCODE_PONG, &ioc->encin= put); + ioc, &ioc->ping_reply, QIO_CHANNEL_WEBSOCK_OPCODE_PONG, + &ioc->encinput); } /* pong frames are ignored */ =20 if (payload_len) { @@ -1176,6 +1188,7 @@ static int qio_channel_websock_close(QIOChannel *ioc, { QIOChannelWebsock *wioc =3D QIO_CHANNEL_WEBSOCK(ioc); =20 + trace_qio_channel_websock_close(ioc); return qio_channel_close(wioc->master, errp); } =20 diff --git a/io/trace-events b/io/trace-events index 6459f71f5b..801b5dcb61 100644 --- a/io/trace-events +++ b/io/trace-events @@ -48,6 +48,11 @@ qio_channel_websock_handshake_pending(void *ioc, int sta= tus) "Websock handshake qio_channel_websock_handshake_reply(void *ioc) "Websock handshake reply io= c=3D%p" qio_channel_websock_handshake_fail(void *ioc, const char *msg) "Websock ha= ndshake fail ioc=3D%p err=3D%s" qio_channel_websock_handshake_complete(void *ioc) "Websock handshake compl= ete ioc=3D%p" +qio_channel_websock_header_partial_decode(void *ioc, size_t payloadlen, un= signed char fin, unsigned char opcode, unsigned char has_mask) "Websocket h= eader decoded ioc=3D%p payload-len=3D%zu fin=3D0x%x opcode=3D0x%x has_mask= =3D0x%x" +qio_channel_websock_header_full_decode(void *ioc, size_t headerlen, size_t= payloadlen, uint32_t mask) "Websocket header decoded ioc=3D%p header-len= =3D%zu payload-len=3D%zu mask=3D0x%x" +qio_channel_websock_payload_decode(void *ioc, uint8_t opcode, size_t paylo= ad_remain) "Websocket header decoded ioc=3D%p opcode=3D0x%x payload-remain= =3D%zu" +qio_channel_websock_encode(void *ioc, uint8_t opcode, size_t payloadlen, s= ize_t headerlen) "Websocket encoded ioc=3D%p opcode=3D0x%x header-len=3D%zu= payload-len=3D%zu" +qio_channel_websock_close(void *ioc) "Websocket close ioc=3D%p" =20 # io/channel-command.c qio_channel_command_new_pid(void *ioc, int writefd, int readfd, int pid) "= Command new pid ioc=3D%p writefd=3D%d readfd=3D%d pid=3D%d" --=20 2.13.5