static void command_eos(char * token, Channel * c) { char id[256]; StreamClient * client = NULL; size_t done = 0; WriteRequest * r = NULL; int err = 0; json_read_string(&c->inp, id, sizeof(id)); 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_WRITE) == 0) err = ERR_UNSUPPORTED; if (!err && !list_is_empty(&client->write_requests)) r = loc_alloc_zero(sizeof(WriteRequest)); if (!err && r == NULL && virtual_stream_add_data(client->stream, NULL, 0, &done, 1) < 0) err = errno; if (r != NULL) { list_init(&r->link_client); r->client = client; r->eos = 1; strncpy(r->token, token, sizeof(r->token) - 1); list_add_last(&r->link_client, &client->write_requests); } else { write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, err); write_stream(&c->out, MARKER_EOM); } }
int virtual_stream_eos(Channel * c, char * token, char * id) { size_t done = 0; WriteRequest * r = NULL; int err = 0; StreamClient * client = find_client(id, c); if (client == NULL) err = errno; if (!err && (client->stream->access & VS_ENABLE_REMOTE_WRITE) == 0) err = ERR_UNSUPPORTED; if (!err && !list_is_empty(&client->write_requests)) r = (WriteRequest *)loc_alloc_zero(sizeof(WriteRequest)); if (!err && r == NULL && virtual_stream_add_data(client->stream, NULL, 0, &done, 1) < 0) err = errno; if (r != NULL) { list_init(&r->link_client); r->client = client; r->eos = 1; strlcpy(r->token, token, sizeof(r->token)); list_add_last(&r->link_client, &client->write_requests); } else if (err == 0) { write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, err); write_stream(&c->out, MARKER_EOM); } if (err != 0) errno = err; return err == 0 ? 0 : -1; }
int virtual_stream_get_data(VirtualStream * stream, char * buf, size_t buf_size, size_t * data_size, int * eos) { size_t len; assert(stream->magic == STREAM_MAGIC); len = (stream->buf_inp + stream->buf_len - stream->buf_out) % stream->buf_len; if (len > buf_size) { len = buf_size; *eos = 0; } else { *eos = stream->eos_inp; } *data_size = len; if (*eos) stream->eos_out = 1; if (stream->buf_out + len <= stream->buf_len) { memcpy(buf, stream->buf + stream->buf_out, len); } else { size_t x = stream->buf_len - stream->buf_out; size_t y = len - x; memcpy(buf, stream->buf + stream->buf_out, x); memcpy(buf + x, stream->buf, y); } if (stream->access & VS_ENABLE_REMOTE_WRITE) { LINK * l; for (l = stream->clients.next; l != &stream->clients; l = l->next) { StreamClient * client = stream2client(l); if (!list_is_empty(&client->write_requests)) { WriteRequest * r = client2write_request(client->write_requests.next); size_t done = 0; int error = 0; if (virtual_stream_add_data(client->stream, r->data + r->offs, r->size - r->offs, &done, r->eos) < 0) error = errno; r->offs += done; if (error || r->offs >= r->size) { delete_write_request(r, error); } while (error && !list_is_empty(&client->write_requests)) { r = client2write_request(client->write_requests.next); delete_write_request(r, ERR_COMMAND_CANCELLED); } } } } if ((stream->access & VS_ENABLE_REMOTE_READ) == 0 && len > 0) { stream->buf_out = (stream->buf_out + len) % stream->buf_len; assert(!*eos || stream->buf_out == stream->buf_inp); if (!stream->space_available_posted) { post_event(notify_space_available, stream); stream->space_available_posted = 1; } } return 0; }
static void process_output_streams_callback(VirtualStream * stream, int event_code, void * args) { ProcessOutput * out = (ProcessOutput *)args; assert(out->vstream == stream); if (!out->req_posted) { int buf_len = out->req.u.fio.rval; int err = 0; int eos = 0; if (buf_len < 0) { buf_len = 0; err = out->req.error; } if (buf_len == 0) eos = 1; if (out->prs == NULL) { eos = 1; err = 0; } assert(buf_len <= sizeof(out->buf)); assert(out->buf_pos <= (size_t)buf_len); assert(out->req.u.fio.bufp == out->buf); #ifdef __linux if (err == EIO) err = 0; #endif if (err) trace(LOG_ALWAYS, "Can't read process output stream: %d %s", err, errno_to_str(err)); if (out->buf_pos < (size_t)buf_len || out->eos != eos) { size_t done = 0; virtual_stream_add_data(stream, out->buf + out->buf_pos, buf_len - out->buf_pos, &done, eos); out->buf_pos += done; if (eos) out->eos = 1; } if (out->buf_pos >= (size_t)buf_len) { if (!eos) { out->req_posted = 1; async_req_post(&out->req); } else if (virtual_stream_is_empty(stream)) { if (out->prs != NULL) { if (out == out->prs->out_struct) out->prs->out_struct = NULL; if (out == out->prs->err_struct) out->prs->err_struct = NULL; } virtual_stream_delete(stream); loc_free(out); } } } }
static void command_write(char * token, Channel * c) { char id[256]; StreamClient * client = NULL; long size = 0; long offs = 0; char * data = 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_long(&c->inp); if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); client = find_client(id, c); if (client == NULL) err = errno; if (!err && (client->stream->access & VS_ENABLE_REMOTE_WRITE) == 0) err = ERR_UNSUPPORTED; { JsonReadBinaryState state; unsigned data_pos = 0; if (!err && !list_is_empty(&client->write_requests)) data = loc_alloc(size); json_read_binary_start(&state, &c->inp); for (;;) { if (data != NULL) { size_t rd = json_read_binary_data(&state, data + data_pos, size - offs - data_pos); if (rd == 0) break; data_pos += rd; } else { char buf[256]; size_t rd = json_read_binary_data(&state, buf, sizeof(buf)); if (rd == 0) break; if (!err) { size_t done = 0; if (virtual_stream_add_data(client->stream, buf, rd, &done, 0) < 0) err = errno; assert(done <= rd); offs += done; if (!err && done < rd) { data = loc_alloc(size - offs); memcpy(data, buf + done, rd - done); data_pos = rd - done; } } } } json_read_binary_end(&state); } if (read_stream(&c->inp) != 0) exception(ERR_JSON_SYNTAX); if (read_stream(&c->inp) != MARKER_EOM) exception(ERR_JSON_SYNTAX); if (data != NULL) { WriteRequest * r = loc_alloc_zero(sizeof(WriteRequest)); list_init(&r->link_client); r->client = client; r->data = data; r->size = size - offs; strncpy(r->token, token, sizeof(r->token) - 1); list_add_last(&r->link_client, &client->write_requests); } else { write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, err); write_stream(&c->out, MARKER_EOM); } }
int virtual_stream_write(Channel * c, char * token, char * id, size_t size, InputStream * inp) { char * data = NULL; int err = 0; long offs = 0; StreamClient * client = find_client(id, c); if (client == NULL) err = errno; if (!err && (client->stream->access & VS_ENABLE_REMOTE_WRITE) == 0) err = ERR_UNSUPPORTED; { JsonReadBinaryState state; size_t data_pos = 0; if (!err && !list_is_empty(&client->write_requests)) data = (char *)loc_alloc(size); json_read_binary_start(&state, inp); for (;;) { if (data != NULL) { size_t rd = json_read_binary_data(&state, data + data_pos, size - offs - data_pos); if (rd == 0) break; data_pos += rd; } else { char buf[256]; size_t rd = json_read_binary_data(&state, buf, sizeof(buf)); if (rd == 0) break; if (!err) { size_t done = 0; if (virtual_stream_add_data(client->stream, buf, rd, &done, 0) < 0) err = errno; assert(done <= rd); offs += done; if (!err && done < rd) { data = (char *)loc_alloc(size - offs); memcpy(data, buf + done, rd - done); data_pos = rd - done; } } } } json_read_binary_end(&state); } if (data != NULL) { WriteRequest * r = (WriteRequest *)loc_alloc_zero(sizeof(WriteRequest)); list_init(&r->link_client); r->client = client; r->data = data; r->size = size - offs; strlcpy(r->token, token, sizeof(r->token)); list_add_last(&r->link_client, &client->write_requests); } else if (err == 0) { write_stringz(&c->out, "R"); write_stringz(&c->out, token); write_errno(&c->out, err); write_stream(&c->out, MARKER_EOM); } if (err != 0) errno = err; return err == 0 ? 0 : -1; }