Пример #1
0
static void conn_send(struct vlc_h2_frame *f)
{
    assert(f != NULL);

    size_t len = vlc_h2_frame_size(f);
    ssize_t val = write(external_fd, f->data, len);
    assert((size_t)val == len);
    free(f);
}
Пример #2
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;
}
Пример #3
0
/**
 * Sends one HTTP/2 frame through TLS.
 *
 * This function sends a whole HTTP/2 frame through a TLS session, then
 * releases the memory used by the frame.
 *
 * The caller must "own" the write side of the TLS session.
 *
 * @note This is a blocking function and may be a thread cancellation point.
 *
 * @return 0 on success, -1 if the connection failed
 */
static int vlc_h2_frame_send(struct vlc_tls *tls, struct vlc_h2_frame *f)
{
    size_t len = vlc_h2_frame_size(f);
    ssize_t val;

    vlc_cleanup_push(free, f);
    val = vlc_https_send(tls, f->data, len);
    vlc_cleanup_pop();
    free(f);

    return ((size_t)val == len) ? 0 : -1;
}
Пример #4
0
/** Queues one outgoing HTTP/2. */
static int vlc_h2_output_queue(struct vlc_h2_output *out,
                               struct vlc_h2_queue *q, struct vlc_h2_frame *f)
{
    if (unlikely(f == NULL))
        return -1; /* memory error */

    /* Iterate the list to count size and find tail pointer */
    struct vlc_h2_frame **lastp = &f;
    size_t len = 0;

    do
    {
        struct vlc_h2_frame *n = *lastp;

        len += vlc_h2_frame_size(n);
        lastp = &n->next;
    }
    while (*lastp != NULL);

    vlc_mutex_lock(&out->lock);
    if (out->failed)
        goto error;

    out->size += len;
    if (out->size >= VLC_H2_MAX_QUEUE)
    {   /* The queue is full. This should never happen but it can be triggered
         * by an evil peer at the other end (e.g. sending a lot of pings and
         * never receiving pongs. Returning an error is better than filling
         * all memory. */
        out->size -= len;
        goto error;
    }

    assert(*(q->last) == NULL);
    *(q->last) = f;
    q->last = lastp;
    vlc_cond_signal(&out->wait);
    vlc_mutex_unlock(&out->lock);
    return 0;

error:
    vlc_mutex_unlock(&out->lock);
    while (f != NULL)
    {
        struct vlc_h2_frame *n = f->next;

        free(f);
        f = n;
    }
    return -1;
}
Пример #5
0
/** Dequeues one outgoing HTTP/2. */
static struct vlc_h2_frame *vlc_h2_output_dequeue(struct vlc_h2_output *out)
{
    struct vlc_h2_queue *q;
    struct vlc_h2_frame *frame;
    size_t len;

    vlc_mutex_lock(&out->lock);

    for (;;)
    {
        q = &out->prio;
        if (q->first != NULL)
            break;

        q = &out->queue;
        if (q->first != NULL)
            break;

        if (unlikely(out->closing))
        {
            vlc_mutex_unlock(&out->lock);
            return NULL;
        }

        int canc = vlc_savecancel();
        vlc_cond_wait(&out->wait, &out->lock);
        vlc_restorecancel(canc);
    }

    frame = q->first;
    q->first = frame->next;
    if (frame->next == NULL)
    {
        assert(q->last == &frame->next);
        q->last = &q->first;
    }
    assert(q->last != &frame->next);

    len = vlc_h2_frame_size(frame);
    assert(out->size >= len);
    out->size -= len;

    vlc_mutex_unlock(&out->lock);

    frame->next = NULL;
    return frame;
}