/** Reports received stream data */
static int vlc_h2_stream_data(void *ctx, struct vlc_h2_frame *f)
{
    struct vlc_h2_stream *s = ctx;
    size_t len;

    if (s->recv_end)
    {
        free(f);
        return vlc_h2_stream_fatal(s, VLC_H2_STREAM_CLOSED);
    }

    /* Enforce the congestion window as required by the protocol spec */
    vlc_h2_frame_data_get(f, &len);
    if (len > s->recv_cwnd)
    {
        free(f);
        s->recv_end = true;
        return vlc_h2_stream_fatal(s, VLC_H2_FLOW_CONTROL_ERROR);
    }
    s->recv_cwnd -= len;

    *(s->recv_tailp) = f;
    s->recv_tailp = &f->next;
    vlc_cond_signal(&s->recv_wait);
    return 0;
}
/**
 * Receives stream data.
 *
 * Dequeues pending incoming data for an HTTP/2 stream. If there is currently
 * no data block, wait for one.
 *
 * \return a VLC data block, or NULL on stream error or end of stream
 */
static block_t *vlc_h2_stream_read(struct vlc_http_stream *stream)
{
    struct vlc_h2_stream *s = (struct vlc_h2_stream *)stream;
    struct vlc_h2_conn *conn = s->conn;
    struct vlc_h2_frame *f;

    vlc_h2_stream_lock(s);
    while ((f = s->recv_head) == NULL && !s->recv_end && !s->interrupted)
    {
        mutex_cleanup_push(&conn->lock);
        vlc_cond_wait(&s->recv_wait, &conn->lock);
        vlc_cleanup_pop();
    }

    if (f == NULL)
    {
        vlc_h2_stream_unlock(s);
        return NULL;
    }

    s->recv_head = f->next;
    if (f->next == NULL)
    {
        assert(s->recv_tailp == &f->next);
        s->recv_tailp = &s->recv_head;
    }

    /* Credit the receive window if missing credit exceeds 50%. */
    uint_fast32_t credit = VLC_H2_INIT_WINDOW - s->recv_cwnd;
    if (credit >= (VLC_H2_INIT_WINDOW / 2)
     && !vlc_h2_output_send(conn->out,
                            vlc_h2_frame_window_update(s->id, credit)))
        s->recv_cwnd += credit;

    vlc_h2_stream_unlock(s);

    /* This, err, unconventional code to avoid copying data. */
    block_t *block = block_heap_Alloc(f, sizeof (*f) + vlc_h2_frame_size(f));
    if (unlikely(block == NULL))
    {
        free(f);
        vlc_h2_stream_error(conn, s->id, VLC_H2_INTERNAL_ERROR);
        return NULL;
    }

    size_t len;
    uint8_t *buf = vlc_h2_frame_data_get(f, &len);

    assert(block->i_buffer >= len);
    assert(block->p_buffer <= buf);
    assert(block->p_buffer + block->i_buffer >= buf + len);
    block->p_buffer = buf;
    block->i_buffer = len;
    return block;
}
Exemple #3
0
static int vlc_h2_stream_data(void *ctx, struct vlc_h2_frame *f)
{
    size_t len;
    const uint8_t *buf = vlc_h2_frame_data_get(f, &len);

    assert(ctx == &stream_cookie);
    assert(len == sizeof (MESSAGE));
    assert(!memcmp(buf, MESSAGE, len));
    stream_blocks++;
    free(f);
    return 0;
}