From 9ded00bcf01d0e825f73832e57c452aaade84b3a Mon Sep 17 00:00:00 2001 From: Lars Lundqvist Date: Wed, 2 Oct 2019 11:17:09 +0200 Subject: [PATCH] curlbasesink: Add curl seek callback Adding functionality to handle SEEK_SET enables rewinding of sent data. In the HTTP case, this happens after an HTTP 401 has been received from the other end. This will result in the sent data being resent. Part-of: --- ext/curl/gstcurlbasesink.c | 56 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/ext/curl/gstcurlbasesink.c b/ext/curl/gstcurlbasesink.c index 16db79daa3..3e7377a71e 100644 --- a/ext/curl/gstcurlbasesink.c +++ b/ext/curl/gstcurlbasesink.c @@ -121,6 +121,8 @@ static size_t gst_curl_base_sink_transfer_read_cb (void *ptr, size_t size, size_t nmemb, void *stream); static size_t gst_curl_base_sink_transfer_write_cb (void *ptr, size_t size, size_t nmemb, void *stream); +static int gst_curl_base_sink_transfer_seek_cb (void *user_p, curl_off_t offset, + int origin); static size_t gst_curl_base_sink_transfer_data_buffer (GstCurlBaseSink * sink, void *curl_ptr, size_t block_size, guint * last_chunk); #ifndef GST_DISABLE_GST_DEBUG @@ -705,6 +707,21 @@ gst_curl_base_sink_transfer_set_common_options_unlocked (GstCurlBaseSink * sink) curl_easy_strerror (res)); return FALSE; } + + res = curl_easy_setopt (sink->curl, CURLOPT_SEEKDATA, sink); + if (res != CURLE_OK) { + sink->error = g_strdup_printf ("failed to set seek user data: %s", + curl_easy_strerror (res)); + return FALSE; + } + res = curl_easy_setopt (sink->curl, CURLOPT_SEEKFUNCTION, + gst_curl_base_sink_transfer_seek_cb); + if (res != CURLE_OK) { + sink->error = g_strdup_printf ("failed to set seek function: %s", + curl_easy_strerror (res)); + return FALSE; + } + /* Time out in case transfer speed in bytes per second stay below * CURLOPT_LOW_SPEED_LIMIT during CURLOPT_LOW_SPEED_TIME */ res = curl_easy_setopt (sink->curl, CURLOPT_LOW_SPEED_LIMIT, 1L); @@ -883,6 +900,45 @@ gst_curl_base_sink_transfer_write_cb (void G_GNUC_UNUSED * ptr, size_t size, return realsize; } +static int +gst_curl_base_sink_transfer_seek_cb (void *stream, curl_off_t offset, + int origin) +{ + GstCurlBaseSink *sink; + curl_off_t buf_size; + + /* + * Origin is SEEK_SET, SEEK_CUR or SEEK_END, + * libcurl currently only passes SEEK_SET. + */ + + sink = (GstCurlBaseSink *) stream; + + GST_OBJECT_LOCK (sink); + buf_size = sink->transfer_buf->offset + sink->transfer_buf->len; + + switch (origin) { + case SEEK_SET: + if ((0 <= offset) && (offset <= buf_size)) { + sink->transfer_buf->offset = offset; + sink->transfer_buf->len = buf_size - offset; + } else { + GST_OBJECT_UNLOCK (sink); + return CURL_SEEKFUNC_FAIL; + } + break; + case SEEK_CUR: + case SEEK_END: + default: + GST_OBJECT_UNLOCK (sink); + return CURL_SEEKFUNC_FAIL; + break; + } + + GST_OBJECT_UNLOCK (sink); + return CURL_SEEKFUNC_OK; +} + CURLcode gst_curl_base_sink_transfer_check (GstCurlBaseSink * sink) {