Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to pause one stream on receive data from server #1600

Closed
nylon009 opened this issue Jul 31, 2021 · 5 comments
Closed

Is it possible to pause one stream on receive data from server #1600

nylon009 opened this issue Jul 31, 2021 · 5 comments
Labels

Comments

@nylon009
Copy link

The device has very limited memory, so we can not download all the response together, we need to pause some stream and resume it later.

For exampele, we play audio on device, we can not download all the audio, need to do it in a streaming way.

We set a ringbuffer to cache the data, if the ringbuffer is full, we need to pause the download of the audio stream, but we cannot block nghttp2_on_data_chunk_recv_callback function to avoid affect other streams.
if the ringbuff is not full, we notify the nghttp2 session to resume the stream.

@JackyYin
Copy link

JackyYin commented Aug 6, 2021

Hi, how about check stream ID before pause it?
something like this:

 if (is_ringbuffer_full(stream_id)) {
    return nghttp2_error.NGHTTP2_ERR_PAUSE;
}

according to the document:

If the application uses nghttp2_session_mem_recv(), it can return nghttp2_error.NGHTTP2_ERR_PAUSE to make nghttp2_session_mem_recv() return without processing further input bytes. The memory by pointed by the data is retained until nghttp2_session_mem_recv() or nghttp2_session_recv() is called.

@JackyYin
Copy link

JackyYin commented Aug 8, 2021

Hi, I have modified examples/libevent-client.c to test this and I think it works.
I am able to read BUFFER_LEN of data into my buffer and process it.
sleep(2) is just for simulate time-consuming processing.

readcb:

static void readcb(struct bufferevent *bev, void *ptr) {
  http2_session_data *session_data = (http2_session_data *)ptr;
  ssize_t readlen;
  struct evbuffer *input = bufferevent_get_input(bev);
  size_t datalen = evbuffer_get_length(input);
  unsigned char *data = evbuffer_pullup(input, -1);

  session_data->accureadlen = 0;
  while (session_data->accureadlen < datalen) {
    readlen = nghttp2_session_mem_recv(session_data->session, data, MIN(datalen, BUFFER_LEN));
    if (readlen < 0) {
      warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
      delete_http2_session_data(session_data);
      return;
    }
    session_data->accureadlen += readlen;
    sleep(2);
  }
  if (evbuffer_drain(input, (size_t)datalen) != 0) {
    warnx("Fatal error: evbuffer_drain failed");
    delete_http2_session_data(session_data);
    return;
  }
  if (session_send(session_data) != 0) {
    delete_http2_session_data(session_data);
    return;
  }
}

on_data_chunk_recv_callback:

static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
                                       int32_t stream_id, const uint8_t *data,
                                       size_t len, void *user_data) {
  http2_session_data *session_data = (http2_session_data *)user_data;
  (void)session;
  (void)flags;

  if (session_data->stream_data->stream_id == stream_id) {
    if (len >= BUFFER_LEN) {
        memcpy(session_data->ring_buffer, &(data[session_data->accureadlen]), BUFFER_LEN);
        fwrite(session_data->ring_buffer, 1, BUFFER_LEN, stdout);
        return NGHTTP2_ERR_PAUSE;
    } else {
        memset(session_data->ring_buffer, 0, BUFFER_LEN);
        memcpy(session_data->ring_buffer, &(data[session_data->accureadlen]), len);
        fwrite(session_data->ring_buffer, 1, len, stdout);
    }
  }
  return 0;
}

@nylon009
Copy link
Author

nylon009 commented Sep 5, 2021

Thanks for your quick response!

But if there are more than one steam are transfering, if the nghttp2_session_mem_recv is return, will other streams been also paused?

If the application uses `nghttp2_session_mem_recv()`, it can return
 :enum:`nghttp2_error.NGHTTP2_ERR_PAUSE` to make
 `nghttp2_session_mem_recv()` return **without processing further
 input bytes**

@JackyYin
Copy link

JackyYin commented Sep 6, 2021

Hi @nevinguo,
I have never tried this before, but I think on_data_chunk_recv_callback is always associated with a particular stream,
so an return of NGHTTP2_ERR_PAUSE should not affect other streams.

Copy link

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.

@github-actions github-actions bot added the Stale label May 21, 2024
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale May 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants