static int send_packet(PortConnection * conn, char * buffer, size_t size) {
    JsonWriteBinaryState state;

    assert (is_dispatch_thread());
    assert (conn->pending_write_request < MAX_STREAM_WRITE);
    protocol_send_command(conn->server->channel, "Streams", "write", write_stream_done,
            conn);
    json_write_string(&conn->server->channel->out, conn->out_stream_id);
    write_stream(&conn->server->channel->out, 0);
    json_write_long(&conn->server->channel->out, size);
    write_stream(&conn->server->channel->out, MARKER_EOA);
    json_write_binary_start(&state, &conn->server->channel->out, size);
    json_write_binary_data(&state, buffer, size);
    json_write_binary_end(&state);
    write_stream(&conn->server->channel->out, MARKER_EOA);
    write_stream(&conn->server->channel->out, MARKER_EOM);
    conn->pending_write_request ++;
    if (conn->pending_write_request  == MAX_STREAM_WRITE) {
        return 0;
    }
    else {
        send_packet_callback(conn, 0);
    }
    return 0;
}
static void send_read_reply(StreamClient * client, char * token, size_t size) {
    VirtualStream * stream = client->stream;
    Channel * c = client->channel;
    unsigned lost = 0;
    unsigned read1 = 0;
    unsigned read2 = 0;
    int eos = 0;
    char * data1 = NULL;
    char * data2 = NULL;
    unsigned pos = 0;
    unsigned len = (stream->buf_inp + stream->buf_len - stream->buf_out) % stream->buf_len;

    assert(len > 0 || stream->eos);
    assert(client->pos <= stream->pos);
    if ((uint64_t)len < stream->pos - client->pos) {
        lost = (long)(stream->pos - client->pos - len);
    }
    else {
        len = (unsigned)(stream->pos - client->pos);
    }
    pos = (stream->buf_inp + stream->buf_len - len) % stream->buf_len;
    if (len > size) len = size;
    data1 = stream->buf + pos;
    if (pos + len <= stream->buf_len) {
        read1 = len;
    }
    else {
        read1 = stream->buf_len - pos;
        data2 = stream->buf;
        read2 = len - read1;
    }
    assert(read1 + read2 == len);
    client->pos += lost + read1 + read2;
    assert(client->pos <= stream->pos);
    if (client->pos == stream->pos && stream->eos) eos = 1;
    assert(eos || lost + read1 + read2 > 0);

    write_stringz(&c->out, "R");
    write_stringz(&c->out, token);
    if (read1 + read2 > 0) {
        JsonWriteBinaryState state;

        json_write_binary_start(&state, &c->out, read1 + read2);
        json_write_binary_data(&state, data1, read1);
        json_write_binary_data(&state, data2, read2);
        json_write_binary_end(&state);
        write_stream(&c->out, 0);
    }
    else {
        write_stringz(&c->out, "null");
    }
    write_errno(&c->out, 0);
    json_write_long(&c->out, lost);
    write_stream(&c->out, 0);
    json_write_boolean(&c->out, eos);
    write_stream(&c->out, 0);
    write_stream(&c->out, MARKER_EOM);
    flush_stream(&c->out);
}
static void safe_memory_get(void * parm) {
    MemoryCommandArgs * args = (MemoryCommandArgs *)parm;
    Channel * c = args->c;
    Context * ctx = args->ctx;

    if (!is_channel_closed(c)) {
        Trap trap;
        if (set_trap(&trap)) {
            OutputStream * out = &args->c->out;
            char * token = args->token;
            ContextAddress addr0 = args->addr;
            ContextAddress addr = args->addr;
            unsigned long size = args->size;
            unsigned long pos = 0;
            char buf[BUF_SIZE];
            int err = 0;
            MemoryErrorInfo err_info;
            JsonWriteBinaryState state;

            memset(&err_info, 0, sizeof(err_info));
            if (ctx->exiting || ctx->exited) err = ERR_ALREADY_EXITED;

            write_stringz(out, "R");
            write_stringz(out, token);

            json_write_binary_start(&state, out, size);
            while (pos < size) {
                int rd = size - pos;
                if (rd > BUF_SIZE) rd = BUF_SIZE;
                /* TODO: word size, mode */
                memset(buf, 0, rd);
                if (err == 0) {
                    if (context_read_mem(ctx, addr, buf, rd) < 0) {
                        err = errno;
#if ENABLE_ExtendedMemoryErrorReports
                        context_get_mem_error_info(&err_info);
#endif
                    }
                    else {
                        addr += rd;
                    }
                }
                json_write_binary_data(&state, buf, rd);
                pos += rd;
            }
            json_write_binary_end(&state);
            write_stream(out, 0);

            write_errno(out, err);
            if (err == 0) {
                write_stringz(out, "null");
            }
            else {
                write_ranges(out, addr0, (int)(addr - addr0), BYTE_CANNOT_READ, &err_info);
            }
            write_stream(out, MARKER_EOM);
            clear_trap(&trap);
        }
        else {
            trace(LOG_ALWAYS, "Exception in Memory.get: %s", errno_to_str(trap.error));
            channel_close(c);
        }
    }
    channel_unlock(c);
    context_unlock(ctx);
    loc_free(args);
}