int virtual_stream_read(Channel * c, char * token, char * id, size_t size) { int err = 0; StreamClient * client = find_client(id, c); if (client == NULL) err = errno; if (!err && (client->stream->access & VS_ENABLE_REMOTE_READ) == 0) err = ERR_UNSUPPORTED; if (err == 0) { VirtualStream * stream = client->stream; if (client->pos == stream->pos && !stream->eos_inp) { ReadRequest * r = (ReadRequest *)loc_alloc_zero(sizeof(ReadRequest)); list_init(&r->link_client); r->client = client; r->size = size; strlcpy(r->token, token, sizeof(r->token)); list_add_last(&r->link_client, &client->read_requests); } else { assert(list_is_empty(&client->read_requests)); assert(client->channel == c); send_read_reply(client, token, size); advance_stream_buffer(stream); } } else errno = err; return err == 0 ? 0 : -1; }
int virtual_stream_add_data(VirtualStream * stream, char * buf, size_t buf_size, size_t * data_size, int eos) { int err = 0; assert(stream->magic == STREAM_MAGIC); if (stream->eos_inp) err = ERR_EOF; if (!err) { size_t len = (stream->buf_out + stream->buf_len - stream->buf_inp - 1) % stream->buf_len; assert(len < stream->buf_len); if (buf_size < len) len = buf_size; if (stream->buf_inp + len <= stream->buf_len) { memcpy(stream->buf + stream->buf_inp, buf, len); } else { size_t x = stream->buf_len - stream->buf_inp; size_t y = len - x; memcpy(stream->buf + stream->buf_inp, buf, x); memcpy(stream->buf, buf + x, y); } stream->buf_inp = (stream->buf_inp + len) % stream->buf_len; stream->pos += len; *data_size = len; if (eos && buf_size == len) stream->eos_inp = 1; } if (stream->access & VS_ENABLE_REMOTE_READ) { if (!err && (stream->eos_inp || *data_size > 0)) { LINK * l; for (l = stream->clients.next; l != &stream->clients; l = l->next) { StreamClient * client = stream2client(l); while (!list_is_empty(&client->read_requests) && (client->pos < stream->pos || stream->eos_inp)) { ReadRequest * r = client2read_request(client->read_requests.next); list_remove(&r->link_client); send_read_reply(client, r->token, r->size); loc_free(r); } } advance_stream_buffer(stream); } } else if (!stream->data_available_posted) { post_event(notify_data_available, stream); stream->data_available_posted = 1; } errno = err; return err ? -1 : 0; }
static void command_read(char * token, Channel * c) { char id[256]; size_t size = 0; StreamClient * client = NULL; int err = 0; json_read_string(&c->inp, id, sizeof(id)); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); size = json_read_ulong(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); client = find_client(id, c); if (client == NULL) err = errno; if (!err && (client->stream->access & VS_ENABLE_REMOTE_READ) == 0) err = ERR_UNSUPPORTED; if (err == 0) { VirtualStream * stream = client->stream; if (client->pos == stream->pos && !stream->eos) { ReadRequest * r = loc_alloc_zero(sizeof(ReadRequest)); list_init(&r->link_client); r->client = client; r->size = size; strncpy(r->token, token, sizeof(r->token) - 1); list_add_last(&r->link_client, &client->read_requests); } else { assert(list_is_empty(&client->read_requests)); assert(client->channel == c); send_read_reply(client, token, size); advance_stream_buffer(stream); } } else { write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_stringz(&c->out, "null"); write_errno(&c->out, err); json_write_long(&c->out, 0); write_stream(&c->out, 0); json_write_boolean(&c->out, 0); write_stream(&c->out, 0); write_stream(&c->out, MARKER_EOM); } }
static void delete_client(StreamClient * client) { VirtualStream * stream = client->stream; Trap trap; LINK * n; assert(stream->ref_cnt > 0); if (set_trap(&trap)) { send_event_stream_disposed(&client->channel->out, stream); clear_trap(&trap); } else { trace(LOG_ALWAYS, "Exception sending stream deleted event: %d %s", trap.error, errno_to_str(trap.error)); } list_remove(&client->link_hash); list_remove(&client->link_stream); list_remove(&client->link_all); for (n = client->read_requests.next; n != &client->read_requests;) { ReadRequest * r = client2read_request(n); n = n->next; delete_read_request(r); } for (n = client->write_requests.next; n != &client->write_requests;) { WriteRequest * r = client2write_request(n); n = n->next; delete_write_request(r, ERR_COMMAND_CANCELLED); } loc_free(client); if (--stream->ref_cnt == 0) { assert(list_is_empty(&stream->clients)); assert(stream->deleted); post_event(delete_stream, stream); } else if (stream->access & VS_ENABLE_REMOTE_READ) { advance_stream_buffer(stream); } }