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 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); } }