示例#1
0
文件: octstr.c 项目: dzruyk/crypti
char *
octstr_snprintf(octstr_t *octstr, char *fmt, ...)
{
	assert(octstr != NULL);

	size_t res, new_res;
	va_list ap, ap_copy;

	va_start(ap, fmt);
	va_copy(ap_copy, ap);
	buffer_reset(octstr->buf);
	buffer_advance(octstr->buf, OCTSTR_SNPRINTF_ADVANCE);
	res = vsnprintf(buffer_ptr(octstr->buf), OCTSTR_SNPRINTF_ADVANCE, fmt, ap);
	if (res < 0)
		error(1, "octstr_snprintf: vsnprintf res=%d", (int)res);
	if (res >= OCTSTR_SNPRINTF_ADVANCE) {
		buffer_reset(octstr->buf);
		buffer_advance(octstr->buf, res+1); /* plus one zero char */
		new_res = vsnprintf(buffer_ptr(octstr->buf), res+1, fmt, ap_copy);
		if (new_res < 0 || new_res != res)
			error(1, "octstr_snprintf: should not reach");
	} else
		buffer_trim(octstr->buf, OCTSTR_SNPRINTF_ADVANCE - res);
	/* now reduce buffer size down one byte because we have '\0' there */
	buffer_trim(octstr->buf, 1);
	va_end(ap);
	return buffer_ptr(octstr->buf);
}
示例#2
0
/*
 * The function assumes that the following patterns have fixed sizes:
 * - "BeginString=" ("8=") is 2 bytes long
 * - "CheckSum=" ("10=") is 3 bytes long
 * - "MsgType=" ("35=") is 3 bytes long
 */
static bool checksum(struct fix_message *self, struct buffer *buffer)
{
	const char *start;
	int offset;

	start = buffer_start(buffer);

	/* The number of bytes between tag MsgType and buffer's start */
	offset = start - (self->msg_type - 3);

	/*
	 * Checksum tag and its trailing delimiter increase
	 * the message's length by seven bytes - "10=***\x01"
	 */
	if (buffer_size(buffer) + offset < self->body_length + 7)
		return false;

	/* Buffer's start will point to the CheckSum tag */
	buffer_advance(buffer, self->body_length - offset);

	self->check_sum = parse_field(buffer, CheckSum);
	if (!self->check_sum)
		return false;

	if (!verify_checksum(self, buffer))
		return false;

	/* Go back to analyze other fields */
	buffer_advance(buffer, start - buffer_start(buffer));

	return true;
}
示例#3
0
文件: vnc-ws.c 项目: bertogg/qemu
long vnc_client_read_ws(VncState *vs)
{
    int ret, err;
    uint8_t *payload;
    size_t payload_size, header_size;
    VNC_DEBUG("Read websocket %p size %zd offset %zd\n", vs->ws_input.buffer,
            vs->ws_input.capacity, vs->ws_input.offset);
    buffer_reserve(&vs->ws_input, 4096);
    ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096);
    if (!ret) {
        return 0;
    }
    vs->ws_input.offset += ret;

    ret = 0;
    /* consume as much of ws_input buffer as possible */
    do {
        if (vs->ws_payload_remain == 0) {
            err = vncws_decode_frame_header(&vs->ws_input,
                                            &header_size,
                                            &vs->ws_payload_remain,
                                            &vs->ws_payload_mask);
            if (err <= 0) {
                return err;
            }

            buffer_advance(&vs->ws_input, header_size);
        }
        if (vs->ws_payload_remain != 0) {
            err = vncws_decode_frame_payload(&vs->ws_input,
                                             &vs->ws_payload_remain,
                                             &vs->ws_payload_mask,
                                             &payload,
                                             &payload_size);
            if (err < 0) {
                return err;
            }
            if (err == 0) {
                return ret;
            }
            ret += err;

            buffer_reserve(&vs->input, payload_size);
            buffer_append(&vs->input, payload, payload_size);

            buffer_advance(&vs->ws_input, payload_size);
        }
    } while (vs->ws_input.offset > 0);

    return ret;
}
示例#4
0
int boe_message_decode(struct buffer *buf, struct boe_message *msg, size_t size)
{
	u16 magic, len;
	void *start;
	size_t count;

	start = buffer_start(buf);

	magic = buffer_get_le16(buf);
	if (magic != BOE_MAGIC)
		return -1;

	len = buffer_get_le16(buf);

	count = BOE_MAGIC_LEN + len;

	if (count > size)
		count = size;

	memcpy(msg, start, count);

	buffer_advance(buf, len - BOE_MSG_LENGTH_LEN);

	return 0;
}
示例#5
0
文件: vnc-ws.c 项目: MauroZurita/qemu
void vncws_handshake_read(void *opaque)
{
    VncState *vs = opaque;
    uint8_t *handshake_end;
    long ret;
    buffer_reserve(&vs->ws_input, 4096);
    ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096);

    if (!ret) {
        if (vs->csock == -1) {
            vnc_disconnect_finish(vs);
        }
        return;
    }
    vs->ws_input.offset += ret;

    handshake_end = (uint8_t *)g_strstr_len((char *)vs->ws_input.buffer,
            vs->ws_input.offset, WS_HANDSHAKE_END);
    if (handshake_end) {
        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
        vncws_process_handshake(vs, vs->ws_input.buffer, vs->ws_input.offset);
        buffer_advance(&vs->ws_input, handshake_end - vs->ws_input.buffer +
                strlen(WS_HANDSHAKE_END));
    }
}
示例#6
0
文件: vnc-ws.c 项目: MauroZurita/qemu
long vnc_client_read_ws(VncState *vs)
{
    int ret, err;
    uint8_t *payload;
    size_t payload_size, frame_size;
    VNC_DEBUG("Read websocket %p size %zd offset %zd\n", vs->ws_input.buffer,
            vs->ws_input.capacity, vs->ws_input.offset);
    buffer_reserve(&vs->ws_input, 4096);
    ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), 4096);
    if (!ret) {
        return 0;
    }
    vs->ws_input.offset += ret;

    /* make sure that nothing is left in the ws_input buffer */
    do {
        err = vncws_decode_frame(&vs->ws_input, &payload,
                              &payload_size, &frame_size);
        if (err <= 0) {
            return err;
        }

        buffer_reserve(&vs->input, payload_size);
        buffer_append(&vs->input, payload, payload_size);

        buffer_advance(&vs->ws_input, frame_size);
    } while (vs->ws_input.offset > 0);

    return ret;
}
struct itch50_message *itch50_message_decode(struct buffer *buf)
{
	size_t available;
	size_t size;
	void *start;
	u8 type;

	available = buffer_size(buf);

	if (!available)
		return NULL;

	type = buffer_peek_8(buf);

	size = itch50_message_size(type);
	if (!size)
		return NULL;

	if (available < size)
		return NULL;

	start = buffer_start(buf);

	buffer_advance(buf, size);

	return start;
}
示例#8
0
int fix_message_parse(struct fix_message *self, struct buffer *buffer)
{
	unsigned long size;
	const char *start;

	self->head_buf = buffer;

retry:
	start	= buffer_start(buffer);
	size	= buffer_size(buffer);

	if (!size)
		goto fail;

	if (!first_three_fields(self))
		goto fail;

	if (!checksum(self, buffer))
		goto fail;

	rest_of_message(self, buffer);

	return 0;

fail:
	if (size > FIX_MAX_MESSAGE_SIZE)
		goto retry;

	buffer_advance(buffer, start - buffer_start(buffer));

	return -1;
}
示例#9
0
static ssize_t qio_channel_websock_write_wire(QIOChannelWebsock *ioc,
                                              Error **errp)
{
    ssize_t ret;
    ssize_t done = 0;
    qio_channel_websock_encode(ioc);

    while (ioc->encoutput.offset > 0) {
        ret = qio_channel_write(ioc->master,
                                (char *)ioc->encoutput.buffer,
                                ioc->encoutput.offset,
                                errp);
        if (ret < 0) {
            if (ret == QIO_CHANNEL_ERR_BLOCK &&
                done > 0) {
                return done;
            } else {
                return ret;
            }
        }
        buffer_advance(&ioc->encoutput, ret);
        done += ret;
    }
    return done;
}
示例#10
0
文件: xen_console.c 项目: 8tab/qemu
static void xencons_send(struct XenConsole *con)
{
    ssize_t len, size;

    size = con->buffer.size - con->buffer.consumed;
    if (qemu_chr_fe_backend_connected(&con->chr)) {
        len = qemu_chr_fe_write(&con->chr,
                                con->buffer.data + con->buffer.consumed,
                                size);
    } else {
        len = size;
    }
    if (len < 1) {
        if (!con->backlog) {
            con->backlog = 1;
            xen_pv_printf(&con->xendev, 1,
                          "backlog piling up, nobody listening?\n");
        }
    } else {
        buffer_advance(&con->buffer, len);
        if (con->backlog && len == size) {
            con->backlog = 0;
            xen_pv_printf(&con->xendev, 1, "backlog is gone\n");
        }
    }
}
示例#11
0
int fix_message_parse(struct fix_message *self, struct buffer *buffer)
{
	int ret = FIX_MSG_STATE_PARTIAL;
	unsigned long size;
	const char *start;

	self->head_buf = buffer;

retry:
	start	= buffer_start(buffer);
	size	= buffer_size(buffer);

	if (!size)
		goto fail;

	ret = first_three_fields(self);
	if (ret)
		goto fail;

	ret = checksum(self, buffer);
	if (ret)
		goto fail;

	rest_of_message(self, buffer);

	return 0;

fail:
	if (ret != FIX_MSG_STATE_PARTIAL)
		goto retry;

	buffer_advance(buffer, start - buffer_start(buffer));

	return -1;
}
int itch40_message_decode(struct buffer *buf, struct itch40_message *msg)
{
	size_t available;
	size_t size;
	u8 type;

	available = buffer_size(buf);

	if (!available)
		return -1;

	type = buffer_peek_8(buf);

	size = itch40_message_size(type);
	if (!size)
		return -1;

	if (available < size)
		return -1;

	memcpy(msg, buffer_start(buf), size);

	buffer_advance(buf, size);

	return 0;
}
示例#13
0
文件: vnc-ws.c 项目: bertogg/qemu
void vncws_handshake_read(void *opaque)
{
    VncState *vs = opaque;
    uint8_t *handshake_end;
    long ret;
    /* Typical HTTP headers from novnc are 512 bytes, so limiting
     * total header size to 4096 is easily enough. */
    size_t want = 4096 - vs->ws_input.offset;
    buffer_reserve(&vs->ws_input, want);
    ret = vnc_client_read_buf(vs, buffer_end(&vs->ws_input), want);

    if (!ret) {
        if (vs->csock == -1) {
            vnc_disconnect_finish(vs);
        }
        return;
    }
    vs->ws_input.offset += ret;

    handshake_end = (uint8_t *)g_strstr_len((char *)vs->ws_input.buffer,
            vs->ws_input.offset, WS_HANDSHAKE_END);
    if (handshake_end) {
        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
        vncws_process_handshake(vs, vs->ws_input.buffer, vs->ws_input.offset);
        buffer_advance(&vs->ws_input, handshake_end - vs->ws_input.buffer +
                strlen(WS_HANDSHAKE_END));
    } else if (vs->ws_input.offset >= 4096) {
        VNC_DEBUG("End of headers not found in first 4096 bytes\n");
        vnc_client_error(vs);
    }
}
示例#14
0
static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc,
                                                   GIOCondition condition,
                                                   gpointer user_data)
{
    QIOTask *task = user_data;
    QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(
        qio_task_get_source(task));
    Error *err = NULL;
    ssize_t ret;

    ret = qio_channel_write(wioc->master,
                            (char *)wioc->encoutput.buffer,
                            wioc->encoutput.offset,
                            &err);

    if (ret < 0) {
        trace_qio_channel_websock_handshake_fail(ioc);
        qio_task_abort(task, err);
        error_free(err);
        return FALSE;
    }

    buffer_advance(&wioc->encoutput, ret);
    if (wioc->encoutput.offset == 0) {
        trace_qio_channel_websock_handshake_complete(ioc);
        qio_task_complete(task);
        return FALSE;
    }
    trace_qio_channel_websock_handshake_pending(ioc, G_IO_OUT);
    return TRUE;
}
示例#15
0
/*
 * The function assumes that the following patterns have fixed sizes:
 * - "BeginString=" ("8=") is 2 bytes long
 * - "CheckSum=" ("10=") is 3 bytes long
 * - "MsgType=" ("35=") is 3 bytes long
 */
static int checksum(struct fix_message *self, struct buffer *buffer, unsigned long flags)
{
    const char *start;
    int offset;
    int ret;

    start = buffer_start(buffer);

    /* The number of bytes between tag MsgType and buffer's start */
    offset = start - (self->msg_type - 3);

    /*
     * Checksum tag and its trailing delimiter increase
     * the message's length by seven bytes - "10=***\x01"
     */
    if (buffer_size(buffer) + offset < self->body_length + 7) {
        ret = FIX_MSG_STATE_PARTIAL;
        goto exit;
    }

    if (flags & FIX_PARSE_FLAG_NO_CSUM) {
        ret = 0;
        goto exit;
    }

    /* Buffer's start will point to the CheckSum tag */
    buffer_advance(buffer, self->body_length - offset);

    ret = match_field(buffer, CheckSum, &self->check_sum);
    if (ret)
        goto exit;

    if (!verify_checksum(self, buffer)) {
        ret = FIX_MSG_STATE_GARBLED;
        goto exit;
    }

    /* Go back to analyze other fields */
    buffer_advance(buffer, start - buffer_start(buffer));

exit:
    return ret;
}
示例#16
0
char *buffer_find(struct buffer *buf, char c)
{
	while (buffer_first_char(buf) != c) {
		if (!buffer_size(buf))
			return NULL;

		buffer_advance(buf, 1);
	}

	return buffer_start(buf);
}
示例#17
0
char *buffer_find(struct buffer *buf, u8 c)
{
	while (true) {
		if (!buffer_size(buf))
			return NULL;

		if (buffer_peek_8(buf) == c)
			break;

		buffer_advance(buf, 1);
	}

	return buffer_start(buf);
}
示例#18
0
static void next_tag(struct buffer *self)
{
    char *delim;

    delim = buffer_find(self, 0x01);

    if (!delim)
        return;

    if (*delim != 0x01)
        return;

    buffer_advance(self, 1);
}
示例#19
0
static int soupbin3_packet_decode(struct buffer *buf, uint16_t len, struct soupbin3_packet *packet)
{
	size_t size;
	void *start;

	start = buffer_start(buf);

	size = sizeof(uint16_t) + len;

	memcpy(packet, start - sizeof(uint16_t), size);

	buffer_advance(buf, len);

	return 0;
}
示例#20
0
static int parse_value(struct buffer *self, const char **value)
{
	char *start, *end;

	start = buffer_start(self);

	end = buffer_find(self, 0x01);

	if (!end || *end != 0x01)
		return FIX_MSG_STATE_PARTIAL;

	buffer_advance(self, 1);

	*value = start;

	return 0;
}
示例#21
0
static const char *parse_value(struct buffer *self)
{
	char *start, *end;

	start = buffer_start(self);

	end = buffer_find(self, 0x01);

	if (!end)
		return NULL;

	if (*end != 0x01)
		return NULL;

	buffer_advance(self, 1);

	return start;
}
示例#22
0
static ssize_t qio_channel_websock_readv(QIOChannel *ioc,
                                         const struct iovec *iov,
                                         size_t niov,
                                         int **fds,
                                         size_t *nfds,
                                         Error **errp)
{
    QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
    size_t i;
    ssize_t got = 0;
    ssize_t ret;

    if (wioc->io_err) {
        *errp = error_copy(wioc->io_err);
        return -1;
    }

    if (!wioc->rawinput.offset) {
        ret = qio_channel_websock_read_wire(QIO_CHANNEL_WEBSOCK(ioc), errp);
        if (ret < 0) {
            return ret;
        }
    }

    for (i = 0 ; i < niov ; i++) {
        size_t want = iov[i].iov_len;
        if (want > (wioc->rawinput.offset - got)) {
            want = (wioc->rawinput.offset - got);
        }

        memcpy(iov[i].iov_base,
               wioc->rawinput.buffer + got,
               want);
        got += want;

        if (want < iov[i].iov_len) {
            break;
        }
    }

    buffer_advance(&wioc->rawinput, got);
    qio_channel_websock_set_watch(wioc);
    return got;
}
示例#23
0
static ssize_t qio_channel_websock_decode_payload(QIOChannelWebsock *ioc,
                                                  Error **errp)
{
    size_t i;
    size_t payload_len;
    uint32_t *payload32;

    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 = ioc->encinput.offset - (ioc->encinput.offset % 4);
    } else {
        payload_len = ioc->payload_remain;
    }
    if (payload_len == 0) {
        return QIO_CHANNEL_ERR_BLOCK;
    }

    ioc->payload_remain -= payload_len;

    /* unmask frame */
    /* process 1 frame (32 bit op) */
    payload32 = (uint32_t *)ioc->encinput.buffer;
    for (i = 0; i < payload_len / 4; i++) {
        payload32[i] ^= ioc->mask.u;
    }
    /* process the remaining bytes (if any) */
    for (i *= 4; i < payload_len; i++) {
        ioc->encinput.buffer[i] ^= ioc->mask.c[i % 4];
    }

    buffer_reserve(&ioc->rawinput, payload_len);
    buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len);
    buffer_advance(&ioc->encinput, payload_len);
    return payload_len;
}
示例#24
0
int fix_message_parse(struct fix_message *self, struct fix_dialect *dialect, struct buffer *buffer, unsigned long flags)
{
    const char *start;
    int ret;

    self->head_buf = buffer;

    TRACE(LIBTRADING_FIX_MESSAGE_PARSE(self, dialect, buffer));
retry:
    ret = FIX_MSG_STATE_PARTIAL;

    start	= buffer_start(buffer);

    if (!buffer_size(buffer))
        goto fail;

    ret = first_three_fields(self, flags);
    if (ret)
        goto fail;

    ret = checksum(self, buffer, flags);
    if (ret)
        goto fail;

    rest_of_message(self, dialect, buffer);

    self->iov[0].iov_base	= (void *)start;
    self->iov[0].iov_len 	= buffer_start(buffer) - start;

    TRACE(LIBTRADING_FIX_MESSAGE_PARSE_RET());

    return 0;

fail:
    if (ret != FIX_MSG_STATE_PARTIAL)
        goto retry;

    buffer_advance(buffer, start - buffer_start(buffer));

    TRACE(LIBTRADING_FIX_MESSAGE_PARSE_ERR());

    return -1;
}
示例#25
0
文件: vnc-ws.c 项目: bertogg/qemu
long vnc_client_write_ws(VncState *vs)
{
    long ret;
    VNC_DEBUG("Write WS: Pending output %p size %zd offset %zd\n",
              vs->output.buffer, vs->output.capacity, vs->output.offset);
    vncws_encode_frame(&vs->ws_output, vs->output.buffer, vs->output.offset);
    buffer_reset(&vs->output);
    ret = vnc_client_write_buf(vs, vs->ws_output.buffer, vs->ws_output.offset);
    if (!ret) {
        return 0;
    }

    buffer_advance(&vs->ws_output, ret);

    if (vs->ws_output.offset == 0) {
        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
    }

    return ret;
}
示例#26
0
static int qio_channel_websock_handshake_read(QIOChannelWebsock *ioc,
                                              Error **errp)
{
    char *handshake_end;
    ssize_t ret;
    /* Typical HTTP headers from novnc are 512 bytes, so limiting
     * total header size to 4096 is easily enough. */
    size_t want = 4096 - ioc->encinput.offset;
    buffer_reserve(&ioc->encinput, want);
    ret = qio_channel_read(ioc->master,
                           (char *)buffer_end(&ioc->encinput), want, errp);
    if (ret < 0) {
        return -1;
    }
    ioc->encinput.offset += ret;

    handshake_end = g_strstr_len((char *)ioc->encinput.buffer,
                                 ioc->encinput.offset,
                                 QIO_CHANNEL_WEBSOCK_HANDSHAKE_END);
    if (!handshake_end) {
        if (ioc->encinput.offset >= 4096) {
            error_setg(errp,
                       "End of headers not found in first 4096 bytes");
            return -1;
        } else {
            return 0;
        }
    }

    if (qio_channel_websock_handshake_process(ioc,
                                              (char *)ioc->encinput.buffer,
                                              ioc->encinput.offset,
                                              errp) < 0) {
        return -1;
    }

    buffer_advance(&ioc->encinput,
                   handshake_end - (char *)ioc->encinput.buffer +
                   strlen(QIO_CHANNEL_WEBSOCK_HANDSHAKE_END));
    return 1;
}
示例#27
0
ssize_t buffer_inflate(struct buffer *comp_buf, struct buffer *uncomp_buf, z_stream *stream)
{
	unsigned long nr;
	ssize_t ret;
	int err;

	nr = buffer_size(comp_buf);
	if (!nr)
		return 0;

	if (nr > INFLATE_SIZE)
		nr = INFLATE_SIZE;

	stream->avail_in	= nr;
	stream->avail_out	= buffer_remaining(uncomp_buf);
	stream->next_out	= (void *) buffer_end(uncomp_buf);

retry:
	err = inflate(stream, Z_NO_FLUSH);
	switch (err) {
	case Z_STREAM_END:
	case Z_BUF_ERROR:
	case Z_OK:
		/* OK to continue */
		break;
	default:
		return -1;
	}

	if (!err && !stream->avail_out)
		goto retry;

	buffer_advance(comp_buf, nr - stream->avail_in);

	ret = buffer_remaining(uncomp_buf) - stream->avail_out;

	uncomp_buf->end += ret;

	return ret;
}
示例#28
0
static int parse_tag(struct buffer *self, int *tag)
{
    const char *delim;
    const char *start;
    const char *end;
    int ret;

    start = buffer_start(self);
    delim = buffer_find(self, '=');

    if (!delim || *delim != '=')
        return FIX_MSG_STATE_PARTIAL;
    ret = fix_uatoi(start, &end);
    if (end != delim)
        return FIX_MSG_STATE_GARBLED;

    buffer_advance(self, 1);

    *tag = ret;

    return 0;
}
示例#29
0
static int parse_tag(struct buffer *self)
{
	const char *delim;
	const char *start;
	char *end;
	int ret;

	start = buffer_start(self);
	delim = buffer_find(self, '=');

	if (!delim)
		return 0;

	if (*delim != '=')
		return 0;

	ret = strtol(start, &end, 10);
	if (end != delim)
		return 0;

	buffer_advance(self, 1);

	return ret;
}
示例#30
0
static ssize_t qio_channel_websock_decode_header(QIOChannelWebsock *ioc,
                                                 Error **errp)
{
    unsigned char opcode, fin, has_mask;
    size_t header_size;
    size_t payload_len;
    QIOChannelWebsockHeader *header =
        (QIOChannelWebsockHeader *)ioc->encinput.buffer;

    if (ioc->payload_remain) {
        error_setg(errp,
                   "Decoding header but %zu bytes of payload remain",
                   ioc->payload_remain);
        return -1;
    }
    if (ioc->encinput.offset < QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT) {
        /* header not complete */
        return QIO_CHANNEL_ERR_BLOCK;
    }

    fin = (header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN) >>
        QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_FIN;
    opcode = header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE;
    has_mask = (header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK) >>
        QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_HAS_MASK;
    payload_len = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN;

    if (opcode == QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) {
        /* disconnect */
        return 0;
    }

    /* Websocket frame sanity check:
     * * Websocket fragmentation is not supported.
     * * All  websockets frames sent by a client have to be masked.
     * * Only binary encoding is supported.
     */
    if (!fin) {
        error_setg(errp, "websocket fragmentation is not supported");
        return -1;
    }
    if (!has_mask) {
        error_setg(errp, "websocket frames must be masked");
        return -1;
    }
    if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) {
        error_setg(errp, "only binary websocket frames are supported");
        return -1;
    }

    if (payload_len < QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT) {
        ioc->payload_remain = payload_len;
        header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT;
        ioc->mask = header->u.m;
    } else if (payload_len == QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT &&
               ioc->encinput.offset >= QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT) {
        ioc->payload_remain = be16_to_cpu(header->u.s16.l16);
        header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT;
        ioc->mask = header->u.s16.m16;
    } else if (payload_len == QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT &&
               ioc->encinput.offset >= QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT) {
        ioc->payload_remain = be64_to_cpu(header->u.s64.l64);
        header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT;
        ioc->mask = header->u.s64.m64;
    } else {
        /* header not complete */
        return QIO_CHANNEL_ERR_BLOCK;
    }

    buffer_advance(&ioc->encinput, header_size);
    return 1;
}