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); }
/* * 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; }
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; }
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; }
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)); } }
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; }
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; }
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; }
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"); } } }
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; }
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); } }
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; }
/* * 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; }
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); }
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); }
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); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }