/** 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; }
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; }