]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
bufq: change read/write signatures
authorStefan Eissing <stefan@eissing.org>
Thu, 26 Jun 2025 08:26:35 +0000 (10:26 +0200)
committerViktor Szakats <commit@vsz.me>
Fri, 27 Jun 2025 12:16:21 +0000 (14:16 +0200)
Change the signature of `bufq` functions from

* `ssize_t Curl_bufq_*(..., CURLcode *err)` to
* `CURLcode Curl_bufq_*(..., size_t *pn)`

This allows us to write slightly less code and avoids the ssize_t/size_t
conversions in many cases. Also, it gets the function in line with all
the other send/recv signatures.

Added helper functions in `cfilters.h` for sending from/receving into
a bufq.

Fuzzer now fails to build due to these changes and its testing of
the bufq API.

Closes #17396

15 files changed:
lib/bufq.c
lib/bufq.h
lib/cf-h2-proxy.c
lib/cfilters.c
lib/cfilters.h
lib/http2.c
lib/mime.c
lib/request.c
lib/vquic/curl_msh3.c
lib/vquic/curl_ngtcp2.c
lib/vquic/curl_osslq.c
lib/vquic/curl_quiche.c
lib/vtls/vtls.c
lib/ws.c
tests/unit/unit2601.c

index 15c35cef7b9f3e7e5c52fdd58b31e16aeb4deaf2..8783619eed0bbac55c0a1b7aee3c2deb913f693b 100644 (file)
@@ -86,27 +86,26 @@ static size_t chunk_read(struct buf_chunk *chunk,
   }
 }
 
-static ssize_t chunk_slurpn(struct buf_chunk *chunk, size_t max_len,
-                            Curl_bufq_reader *reader,
-                            void *reader_ctx, CURLcode *err)
+static CURLcode chunk_slurpn(struct buf_chunk *chunk, size_t max_len,
+                             Curl_bufq_reader *reader,
+                             void *reader_ctx, size_t *pnread)
 {
   unsigned char *p = &chunk->x.data[chunk->w_offset];
   size_t n = chunk->dlen - chunk->w_offset; /* free amount */
-  ssize_t nread;
+  CURLcode result;
 
+  *pnread = 0;
   DEBUGASSERT(chunk->dlen >= chunk->w_offset);
-  if(!n) {
-    *err = CURLE_AGAIN;
-    return -1;
-  }
+  if(!n)
+    return CURLE_AGAIN;
   if(max_len && n > max_len)
     n = max_len;
-  nread = reader(reader_ctx, p, n, err);
-  if(nread > 0) {
-    DEBUGASSERT((size_t)nread <= n);
-    chunk->w_offset += nread;
+  result = reader(reader_ctx, p, n, pnread);
+  if(!result) {
+    DEBUGASSERT(*pnread <= n);
+    chunk->w_offset += *pnread;
   }
-  return nread;
+  return result;
 }
 
 static void chunk_peek(const struct buf_chunk *chunk,
@@ -361,81 +360,60 @@ static struct buf_chunk *get_non_full_tail(struct bufq *q)
   return chunk;
 }
 
-ssize_t Curl_bufq_write(struct bufq *q,
-                        const unsigned char *buf, size_t len,
-                        CURLcode *err)
+CURLcode Curl_bufq_write(struct bufq *q,
+                         const unsigned char *buf, size_t len,
+                         size_t *pnwritten)
 {
   struct buf_chunk *tail;
-  ssize_t nwritten = 0;
   size_t n;
 
   DEBUGASSERT(q->max_chunks > 0);
+  *pnwritten = 0;
   while(len) {
     tail = get_non_full_tail(q);
     if(!tail) {
-      if((q->chunk_count < q->max_chunks) || (q->opts & BUFQ_OPT_SOFT_LIMIT)) {
-        *err = CURLE_OUT_OF_MEMORY;
-        return -1;
-      }
+      if((q->chunk_count < q->max_chunks) || (q->opts & BUFQ_OPT_SOFT_LIMIT))
+        /* should have gotten a tail, but did not */
+        return CURLE_OUT_OF_MEMORY;
       break;
     }
     n = chunk_append(tail, buf, len);
     if(!n)
       break;
-    nwritten += n;
+    *pnwritten += n;
     buf += n;
     len -= n;
   }
-  if(nwritten == 0 && len) {
-    *err = CURLE_AGAIN;
-    return -1;
-  }
-  *err = CURLE_OK;
-  return nwritten;
+  return (!*pnwritten && len) ? CURLE_AGAIN : CURLE_OK;
 }
 
 CURLcode Curl_bufq_cwrite(struct bufq *q,
                           const char *buf, size_t len,
                           size_t *pnwritten)
 {
-  ssize_t n;
-  CURLcode result;
-  n = Curl_bufq_write(q, (const unsigned char *)buf, len, &result);
-  *pnwritten = (n < 0) ? 0 : (size_t)n;
-  return result;
+  return Curl_bufq_write(q, (const unsigned char *)buf, len, pnwritten);
 }
 
-ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
-                       CURLcode *err)
+CURLcode Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
+                        size_t *pnread)
 {
-  ssize_t nread = 0;
-  size_t n;
-
-  *err = CURLE_OK;
+  *pnread = 0;
   while(len && q->head) {
-    n = chunk_read(q->head, buf, len);
+    size_t n = chunk_read(q->head, buf, len);
     if(n) {
-      nread += n;
+      *pnread += n;
       buf += n;
       len -= n;
     }
     prune_head(q);
   }
-  if(nread == 0) {
-    *err = CURLE_AGAIN;
-    return -1;
-  }
-  return nread;
+  return (!*pnread) ? CURLE_AGAIN : CURLE_OK;
 }
 
 CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len,
                          size_t *pnread)
 {
-  ssize_t n;
-  CURLcode result;
-  n = Curl_bufq_read(q, (unsigned char *)buf, len, &result);
-  *pnread = (n < 0) ? 0 : (size_t)n;
-  return result;
+  return Curl_bufq_read(q, (unsigned char *)buf, len, pnread);
 }
 
 bool Curl_bufq_peek(struct bufq *q,
@@ -487,156 +465,139 @@ void Curl_bufq_skip(struct bufq *q, size_t amount)
   }
 }
 
-ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
-                       void *writer_ctx, CURLcode *err)
+CURLcode Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
+                        void *writer_ctx, size_t *pwritten)
 {
   const unsigned char *buf;
   size_t blen;
-  ssize_t nwritten = 0;
+  CURLcode result = CURLE_OK;
 
+  *pwritten = 0;
   while(Curl_bufq_peek(q, &buf, &blen)) {
-    ssize_t chunk_written;
+    size_t chunk_written;
 
-    chunk_written = writer(writer_ctx, buf, blen, err);
-    if(chunk_written < 0) {
-      if(!nwritten || *err != CURLE_AGAIN) {
-        /* blocked on first write or real error, fail */
-        nwritten = -1;
+    result = writer(writer_ctx, buf, blen, &chunk_written);
+    if(result) {
+      if((result == CURLE_AGAIN) && *pwritten) {
+        /* blocked on subsequent write, report success */
+        result = CURLE_OK;
       }
       break;
     }
     if(!chunk_written) {
-      if(!nwritten) {
+      if(!*pwritten) {
         /* treat as blocked */
-        *err = CURLE_AGAIN;
-        nwritten = -1;
+        result = CURLE_AGAIN;
       }
       break;
     }
-    Curl_bufq_skip(q, (size_t)chunk_written);
-    nwritten += chunk_written;
+    *pwritten += chunk_written;
+    Curl_bufq_skip(q, chunk_written);
   }
-  return nwritten;
+  return result;
 }
 
-ssize_t Curl_bufq_write_pass(struct bufq *q,
-                             const unsigned char *buf, size_t len,
-                             Curl_bufq_writer *writer, void *writer_ctx,
-                             CURLcode *err)
+CURLcode Curl_bufq_write_pass(struct bufq *q,
+                              const unsigned char *buf, size_t len,
+                              Curl_bufq_writer *writer, void *writer_ctx,
+                              size_t *pwritten)
 {
-  ssize_t nwritten = 0, n;
+  CURLcode result = CURLE_OK;
+  size_t n;
 
-  *err = CURLE_OK;
+  *pwritten = 0;
   while(len) {
     if(Curl_bufq_is_full(q)) {
       /* try to make room in case we are full */
-      n = Curl_bufq_pass(q, writer, writer_ctx, err);
-      if(n < 0) {
-        if(*err != CURLE_AGAIN) {
+      result = Curl_bufq_pass(q, writer, writer_ctx, &n);
+      if(result) {
+        if(result != CURLE_AGAIN) {
           /* real error, fail */
-          return -1;
+          return result;
         }
         /* would block, bufq is full, give up */
         break;
       }
     }
 
-    /* Add whatever is remaining now to bufq */
-    n = Curl_bufq_write(q, buf, len, err);
-    if(n < 0) {
-      if(*err != CURLE_AGAIN) {
+    /* Add to bufq as much as there is room for */
+    result = Curl_bufq_write(q, buf, len, &n);
+    if(result) {
+      if(result != CURLE_AGAIN)
         /* real error, fail */
-        return -1;
-      }
-      /* no room in bufq */
-      break;
+        return result;
+      if((result == CURLE_AGAIN) && *pwritten)
+        /* we did write successfully before */
+        result = CURLE_OK;
+      return result;
     }
-    /* edge case of writer returning 0 (and len is >0)
-     * break or we might enter an infinite loop here */
-    if(n == 0)
+    else if(n == 0)
+      /* edge case of writer returning 0 (and len is >0)
+       * break or we might enter an infinite loop here */
       break;
 
-    /* Maybe only part of `data` has been added, continue to loop */
-    buf += (size_t)n;
-    len -= (size_t)n;
-    nwritten += (size_t)n;
+    /* Track what we added to bufq */
+    buf += n;
+    len -= n;
+    *pwritten += n;
   }
 
-  if(!nwritten && len) {
-    *err = CURLE_AGAIN;
-    return -1;
-  }
-  *err = CURLE_OK;
-  return nwritten;
+  return (!*pwritten && len) ? CURLE_AGAIN : CURLE_OK;
 }
 
-ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len,
-                       Curl_bufq_reader *reader, void *reader_ctx,
-                       CURLcode *err)
+CURLcode Curl_bufq_sipn(struct bufq *q, size_t max_len,
+                        Curl_bufq_reader *reader, void *reader_ctx,
+                        size_t *pnread)
 {
   struct buf_chunk *tail = NULL;
-  ssize_t nread;
 
-  *err = CURLE_AGAIN;
+  *pnread = 0;
   tail = get_non_full_tail(q);
   if(!tail) {
-    if(q->chunk_count < q->max_chunks) {
-      *err = CURLE_OUT_OF_MEMORY;
-      return -1;
-    }
+    if(q->chunk_count < q->max_chunks)
+      return CURLE_OUT_OF_MEMORY;
     /* full, blocked */
-    *err = CURLE_AGAIN;
-    return -1;
+    return CURLE_AGAIN;
   }
 
-  nread = chunk_slurpn(tail, max_len, reader, reader_ctx, err);
-  if(nread < 0) {
-    return -1;
-  }
-  else if(nread == 0) {
-    /* eof */
-    *err = CURLE_OK;
-  }
-  return nread;
+  return chunk_slurpn(tail, max_len, reader, reader_ctx, pnread);
 }
 
 /**
  * Read up to `max_len` bytes and append it to the end of the buffer queue.
  * if `max_len` is 0, no limit is imposed and the call behaves exactly
  * the same as `Curl_bufq_slurp()`.
- * Returns the total amount of buf read (may be 0) or -1 on other
- * reader errors.
- * Note that even in case of a -1 chunks may have been read and
+ * Returns the total amount of buf read (may be 0) in `pnread` or error
+ * Note that even in case of an error chunks may have been read and
  * the buffer queue will have different length than before.
  */
-static ssize_t bufq_slurpn(struct bufq *q, size_t max_len,
-                           Curl_bufq_reader *reader, void *reader_ctx,
-                           CURLcode *err)
+static CURLcode bufq_slurpn(struct bufq *q, size_t max_len,
+                            Curl_bufq_reader *reader, void *reader_ctx,
+                            size_t *pnread)
 {
-  ssize_t nread = 0, n;
+  CURLcode result;
 
-  *err = CURLE_AGAIN;
+  *pnread = 0;
   while(1) {
-
-    n = Curl_bufq_sipn(q, max_len, reader, reader_ctx, err);
-    if(n < 0) {
-      if(!nread || *err != CURLE_AGAIN) {
+    size_t n;
+    result = Curl_bufq_sipn(q, max_len, reader, reader_ctx, &n);
+    if(result) {
+      if(!*pnread || result != CURLE_AGAIN) {
         /* blocked on first read or real error, fail */
-        nread = -1;
+        return result;
       }
-      else
-        *err = CURLE_OK;
+      result = CURLE_OK;
       break;
     }
     else if(n == 0) {
       /* eof */
-      *err = CURLE_OK;
+      result = CURLE_OK;
       break;
     }
-    nread += (size_t)n;
+    *pnread += n;
     if(max_len) {
-      DEBUGASSERT((size_t)n <= max_len);
-      max_len -= (size_t)n;
+      DEBUGASSERT(n <= max_len);
+      max_len -= n;
       if(!max_len)
         break;
     }
@@ -644,11 +605,11 @@ static ssize_t bufq_slurpn(struct bufq *q, size_t max_len,
     if(q->tail && !chunk_is_full(q->tail))
       break;
   }
-  return nread;
+  return result;
 }
 
-ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
-                        void *reader_ctx, CURLcode *err)
+CURLcode Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
+                         void *reader_ctx, size_t *pnread)
 {
-  return bufq_slurpn(q, 0, reader, reader_ctx, err);
+  return bufq_slurpn(q, 0, reader, reader_ctx, pnread);
 }
index 665af593f59b8578942479db4576050dfb00f067..63fc9160349d733cecd902ad92ab233d752f30c4 100644 (file)
@@ -163,12 +163,11 @@ bool Curl_bufq_is_full(const struct bufq *q);
 /**
  * Write buf to the end of the buffer queue. The buf is copied
  * and the amount of copied bytes is returned.
- * A return code of -1 indicates an error, setting `err` to the
- * cause. An err of CURLE_AGAIN is returned if the buffer queue is full.
+ * CURLE_AGAIN is returned if the buffer queue is full.
  */
-ssize_t Curl_bufq_write(struct bufq *q,
-                        const unsigned char *buf, size_t len,
-                        CURLcode *err);
+CURLcode Curl_bufq_write(struct bufq *q,
+                         const unsigned char *buf, size_t len,
+                         size_t *pnwritten);
 
 CURLcode Curl_bufq_cwrite(struct bufq *q,
                          const char *buf, size_t len,
@@ -177,11 +176,9 @@ CURLcode Curl_bufq_cwrite(struct bufq *q,
 /**
  * Read buf from the start of the buffer queue. The buf is copied
  * and the amount of copied bytes is returned.
- * A return code of -1 indicates an error, setting `err` to the
- * cause. An err of CURLE_AGAIN is returned if the buffer queue is empty.
  */
-ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
-                        CURLcode *err);
+CURLcode Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
+                        size_t *pnread);
 
 CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len,
                          size_t *pnread);
@@ -208,9 +205,9 @@ bool Curl_bufq_peek_at(struct bufq *q, size_t offset,
  */
 void Curl_bufq_skip(struct bufq *q, size_t amount);
 
-typedef ssize_t Curl_bufq_writer(void *writer_ctx,
+typedef CURLcode Curl_bufq_writer(void *writer_ctx,
                                  const unsigned char *buf, size_t len,
-                                 CURLcode *err);
+                                 size_t *pwritten);
 /**
  * Passes the chunks in the buffer queue to the writer and returns
  * the amount of buf written. A writer may return -1 and CURLE_AGAIN
@@ -220,24 +217,23 @@ typedef ssize_t Curl_bufq_writer(void *writer_ctx,
  * Note that in case of a -1 chunks may have been written and
  * the buffer queue will have different length than before.
  */
-ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
-                       void *writer_ctx, CURLcode *err);
+CURLcode Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer,
+                        void *writer_ctx, size_t *pwritten);
 
-typedef ssize_t Curl_bufq_reader(void *reader_ctx,
-                                 unsigned char *buf, size_t len,
-                                 CURLcode *err);
+typedef CURLcode Curl_bufq_reader(void *reader_ctx,
+                                  unsigned char *buf, size_t len,
+                                  size_t *pnread);
 
 /**
  * Read date and append it to the end of the buffer queue until the
  * reader returns blocking or the queue is full. A reader returns
- * -1 and CURLE_AGAIN to indicate blocking.
- * Returns the total amount of buf read (may be 0) or -1 on other
- * reader errors.
- * Note that in case of a -1 chunks may have been read and
+ * CURLE_AGAIN to indicate blocking.
+ * Returns the total amount of buf read (may be 0) in `pnread` on success.
+ * Note that in case of an error chunks may have been read and
  * the buffer queue will have different length than before.
  */
-ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
-                        void *reader_ctx, CURLcode *err);
+CURLcode Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
+                         void *reader_ctx, size_t *pnread);
 
 /**
  * Read *once* up to `max_len` bytes and append it to the buffer.
@@ -245,9 +241,9 @@ ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader,
  * Returns the total amount of buf read (may be 0) or -1 on other
  * reader errors.
  */
-ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len,
-                       Curl_bufq_reader *reader, void *reader_ctx,
-                       CURLcode *err);
+CURLcode Curl_bufq_sipn(struct bufq *q, size_t max_len,
+                        Curl_bufq_reader *reader, void *reader_ctx,
+                        size_t *pnread);
 
 /**
  * Write buf to the end of the buffer queue.
@@ -256,9 +252,9 @@ ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len,
  * on or is placed into the buffer, depending on `len` and current
  * amount buffered, chunk size, etc.
  */
-ssize_t Curl_bufq_write_pass(struct bufq *q,
-                             const unsigned char *buf, size_t len,
-                             Curl_bufq_writer *writer, void *writer_ctx,
-                             CURLcode *err);
+CURLcode Curl_bufq_write_pass(struct bufq *q,
+                              const unsigned char *buf, size_t len,
+                              Curl_bufq_writer *writer, void *writer_ctx,
+                              size_t *pwritten);
 
 #endif /* HEADER_CURL_BUFQ_H */
index 4aa74f6c92cea6efc5d2f36e7dae04f90b2e2f9d..59322aa9ace7b7c3e4f648a7366ec3427bf59dbc 100644 (file)
@@ -224,41 +224,22 @@ static void drain_tunnel(struct Curl_cfilter *cf,
     Curl_multi_mark_dirty(data);
 }
 
-static ssize_t proxy_nw_in_reader(void *reader_ctx,
-                                  unsigned char *buf, size_t buflen,
-                                  CURLcode *err)
-{
-  struct Curl_cfilter *cf = reader_ctx;
-
-  if(cf) {
-    struct Curl_easy *data = CF_DATA_CURRENT(cf);
-    size_t nread;
-    *err = Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, &nread);
-    CURL_TRC_CF(data, cf, "[0] nw_in_reader(len=%zu) -> %d, %zu",
-                buflen, *err, nread);
-    return *err ? -1 : (ssize_t)nread;
-  }
-  *err = CURLE_FAILED_INIT;
-  return -1;
-}
-
-static ssize_t proxy_h2_nw_out_writer(void *writer_ctx,
-                                      const unsigned char *buf, size_t buflen,
-                                      CURLcode *err)
+static CURLcode proxy_h2_nw_out_writer(void *writer_ctx,
+                                       const unsigned char *buf, size_t buflen,
+                                       size_t *pnwritten)
 {
   struct Curl_cfilter *cf = writer_ctx;
-
+  *pnwritten = 0;
   if(cf) {
     struct Curl_easy *data = CF_DATA_CURRENT(cf);
-    size_t nwritten;
-    *err = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen,
-                             FALSE, &nwritten);
-    CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %zd, %d",
-                buflen, nwritten, *err);
-    return *err ? -1 : (ssize_t)nwritten;
-  }
-  *err = CURLE_FAILED_INIT;
-  return -1;
+    CURLcode result;
+    result = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen,
+                               FALSE, pnwritten);
+    CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %d, %zu",
+                buflen, result, *pnwritten);
+    return result;
+  }
+  return CURLE_FAILED_INIT;
 }
 
 static int proxy_h2_client_new(struct Curl_cfilter *cf,
@@ -403,16 +384,16 @@ static CURLcode proxy_h2_nw_out_flush(struct Curl_cfilter *cf,
                                       struct Curl_easy *data)
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
-  ssize_t nwritten;
+  size_t nwritten;
   CURLcode result;
 
   (void)data;
   if(Curl_bufq_is_empty(&ctx->outbufq))
     return CURLE_OK;
 
-  nwritten = Curl_bufq_pass(&ctx->outbufq, proxy_h2_nw_out_writer, cf,
-                            &result);
-  if(nwritten < 0) {
+  result = Curl_bufq_pass(&ctx->outbufq, proxy_h2_nw_out_writer, cf,
+                          &nwritten);
+  if(result) {
     if(result == CURLE_AGAIN) {
       CURL_TRC_CF(data, cf, "[0] flush nw send buffer(%zu) -> EAGAIN",
                   Curl_bufq_len(&ctx->outbufq));
@@ -468,7 +449,7 @@ static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf,
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
-  ssize_t nread;
+  size_t nread;
 
   /* Process network input buffer fist */
   if(!Curl_bufq_is_empty(&ctx->inbufq)) {
@@ -485,10 +466,10 @@ static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf,
         Curl_bufq_is_empty(&ctx->inbufq) && /* and we consumed our input */
         !Curl_bufq_is_full(&ctx->tunnel.recvbuf)) {
 
-    nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result);
-    CURL_TRC_CF(data, cf, "[0] read %zu bytes nw data -> %zd, %d",
-                Curl_bufq_len(&ctx->inbufq), nread, result);
-    if(nread < 0) {
+    result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
+    CURL_TRC_CF(data, cf, "[0] read %zu bytes nw data -> %d, %zu",
+                Curl_bufq_len(&ctx->inbufq), result, nread);
+    if(result) {
       if(result != CURLE_AGAIN) {
         failf(data, "Failed receiving HTTP2 data");
         return result;
@@ -536,17 +517,18 @@ static ssize_t on_session_send(nghttp2_session *h2,
   struct Curl_cfilter *cf = userp;
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nwritten;
+  size_t nwritten;
   CURLcode result = CURLE_OK;
 
   (void)h2;
   (void)flags;
   DEBUGASSERT(data);
 
-  nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
-                                  proxy_h2_nw_out_writer, cf, &result);
-  if(nwritten < 0) {
+  result = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
+                                proxy_h2_nw_out_writer, cf, &nwritten);
+  if(result) {
     if(result == CURLE_AGAIN) {
+      ctx->nw_out_blocked = 1;
       return NGHTTP2_ERR_WOULDBLOCK;
     }
     failf(data, "Failed sending HTTP2 data");
@@ -556,7 +538,8 @@ static ssize_t on_session_send(nghttp2_session *h2,
   if(!nwritten)
     return NGHTTP2_ERR_WOULDBLOCK;
 
-  return nwritten;
+  return (nwritten  > SSIZE_T_MAX) ?
+    NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nwritten;
 }
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
@@ -806,7 +789,7 @@ static ssize_t tunnel_send_callback(nghttp2_session *session,
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
   struct tunnel_stream *ts;
   CURLcode result;
-  ssize_t nread;
+  size_t nread;
 
   (void)source;
   (void)data;
@@ -820,8 +803,8 @@ static ssize_t tunnel_send_callback(nghttp2_session *session,
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   DEBUGASSERT(ts == &ctx->tunnel);
 
-  nread = Curl_bufq_read(&ts->sendbuf, buf, length, &result);
-  if(nread < 0) {
+  result = Curl_bufq_read(&ts->sendbuf, buf, length, &nread);
+  if(result) {
     if(result != CURLE_AGAIN)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     return NGHTTP2_ERR_DEFERRED;
@@ -831,7 +814,8 @@ static ssize_t tunnel_send_callback(nghttp2_session *session,
 
   CURL_TRC_CF(data, cf, "[%d] tunnel_send_callback -> %zd",
               ts->stream_id, nread);
-  return nread;
+  return (nread  > SSIZE_T_MAX) ?
+    NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nread;
 }
 
 static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
@@ -840,7 +824,7 @@ static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
 {
   struct Curl_cfilter *cf = userp;
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
-  ssize_t nwritten;
+  size_t nwritten;
   CURLcode result;
 
   (void)flags;
@@ -850,14 +834,15 @@ static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
   if(stream_id != ctx->tunnel.stream_id)
     return NGHTTP2_ERR_CALLBACK_FAILURE;
 
-  nwritten = Curl_bufq_write(&ctx->tunnel.recvbuf, mem, len, &result);
-  if(nwritten < 0) {
+  result = Curl_bufq_write(&ctx->tunnel.recvbuf, mem, len, &nwritten);
+  if(result) {
     if(result != CURLE_AGAIN)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
 #ifdef DEBUGBUILD
     nwritten = 0;
 #endif
   }
+  /* tunnel.recbuf has soft limit, any success MUST add all data */
   DEBUGASSERT((size_t)nwritten == len);
   return 0;
 }
@@ -1302,16 +1287,9 @@ static CURLcode tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   CURLcode result = CURLE_AGAIN;
 
   *pnread = 0;
-  if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) {
-    ssize_t nread = Curl_bufq_read(&ctx->tunnel.recvbuf,
-                                   (unsigned char *)buf, len, &result);
-    if(nread < 0)
-      goto out;
-    DEBUGASSERT(nread > 0);
-    *pnread = (size_t)nread;
-  }
-
-  if(!*pnread) {
+  if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf))
+    result = Curl_bufq_cread(&ctx->tunnel.recvbuf, buf, len, pnread);
+  else {
     if(ctx->tunnel.closed) {
       result = h2_handle_tunnel_close(cf, data, pnread);
     }
@@ -1325,7 +1303,6 @@ static CURLcode tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
       result = CURLE_AGAIN;
   }
 
-out:
   CURL_TRC_CF(data, cf, "[%d] tunnel_recv(len=%zu) -> %d, %zu",
               ctx->tunnel.stream_id, len, result, *pnread);
   return result;
@@ -1387,7 +1364,6 @@ static CURLcode cf_h2_proxy_send(struct Curl_cfilter *cf,
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
   struct cf_call_data save;
   int rv;
-  ssize_t nwritten = 0;
   CURLcode result, r2;
 
   (void)eos;
@@ -1404,11 +1380,9 @@ static CURLcode cf_h2_proxy_send(struct Curl_cfilter *cf,
     goto out;
   }
 
-  nwritten = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, &result);
-  CURL_TRC_CF(data, cf, "cf_send(), bufq_write %d, %zd", result, nwritten);
-  if(nwritten >= 0)
-    *pnwritten = (size_t)nwritten;
-  else if(result && (result != CURLE_AGAIN))
+  result = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, pnwritten);
+  CURL_TRC_CF(data, cf, "cf_send(), bufq_write %d, %zd", result, *pnwritten);
+  if(result && (result != CURLE_AGAIN))
     goto out;
 
   if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
@@ -1513,11 +1487,11 @@ static bool proxy_h2_connisalive(struct Curl_cfilter *cf,
        not in use by any other transfer, there should not be any data here,
        only "protocol frames" */
     CURLcode result;
-    ssize_t nread = -1;
+    size_t nread;
 
     *input_pending = FALSE;
-    nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result);
-    if(nread != -1) {
+    result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
+    if(!result) {
       if(proxy_h2_process_pending_input(cf, data, &result) < 0)
         /* immediate error, considered dead */
         alive = FALSE;
index 3d1fb61810245eec5a62abd03a61980b8f158327..2c11ce56e28d1de089984a13f76652cddd9b3c92 100644 (file)
@@ -261,6 +261,66 @@ CURLcode Curl_cf_send(struct Curl_easy *data, int num,
   return CURLE_FAILED_INIT;
 }
 
+struct cf_io_ctx {
+  struct Curl_easy *data;
+  struct Curl_cfilter *cf;
+};
+
+static CURLcode cf_bufq_reader(void *writer_ctx,
+                               unsigned char *buf, size_t blen,
+                               size_t *pnread)
+{
+  struct cf_io_ctx *io = writer_ctx;
+  return Curl_conn_cf_recv(io->cf, io->data, (char *)buf, blen, pnread);
+}
+
+CURLcode Curl_cf_recv_bufq(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           struct bufq *bufq,
+                           size_t maxlen,
+                           size_t *pnread)
+{
+  struct cf_io_ctx io;
+
+  if(!cf || !data) {
+    *pnread = 0;
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+  io.data = data;
+  io.cf = cf;
+  return Curl_bufq_sipn(bufq, maxlen, cf_bufq_reader, &io, pnread);
+}
+
+static CURLcode cf_bufq_writer(void *writer_ctx,
+                               const unsigned char *buf, size_t buflen,
+                               size_t *pnwritten)
+{
+  struct cf_io_ctx *io = writer_ctx;
+  return Curl_conn_cf_send(io->cf, io->data, (const char *)buf,
+                           buflen, FALSE, pnwritten);
+}
+
+CURLcode Curl_cf_send_bufq(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           struct bufq *bufq,
+                           const unsigned char *buf, size_t blen,
+                           size_t *pnwritten)
+{
+  struct cf_io_ctx io;
+
+  if(!cf || !data) {
+    *pnwritten = 0;
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+  io.data = data;
+  io.cf = cf;
+  if(buf && blen)
+    return Curl_bufq_write_pass(bufq, buf, blen, cf_bufq_writer, &io,
+                                pnwritten);
+  else
+    return Curl_bufq_pass(bufq, cf_bufq_writer, &io, pnwritten);
+}
+
 CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
                         const struct Curl_cftype *cft,
                         void *ctx)
index 97d0d5bf6981f4f11fe508a8d7f6e79223244b1a..3c49e15005909bbc3fb473d4a5f738395ccfe99d 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "curlx/timediff.h"
 
+struct bufq;
 struct Curl_cfilter;
 struct Curl_easy;
 struct Curl_dns_entry;
@@ -477,6 +478,28 @@ CURLcode Curl_cf_send(struct Curl_easy *data, int sockindex,
                       const void *buf, size_t len, bool eos,
                       size_t *pnwritten);
 
+/**
+ * Receive bytes from connection filter `cf` into `bufq`.
+ * Convenience wrappter around `Curl_bufq_sipn()`,
+ * so users do not have to implement a callback.
+ */
+CURLcode Curl_cf_recv_bufq(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           struct bufq *bufq,
+                           size_t maxlen,
+                           size_t *pnread);
+
+/**
+ * Send bytes in `bufq` using connection filter `cf`.
+ * A convenience wrapper around `Curl_bufq_write_pass()`,
+ * so users do not have to implement a callback.
+ */
+CURLcode Curl_cf_send_bufq(struct Curl_cfilter *cf,
+                           struct Curl_easy *data,
+                           struct bufq *bufq,
+                           const unsigned char *buf, size_t blen,
+                           size_t *pnwritten);
+
 /**
  * Notify connection filters that they need to setup data for
  * a transfer.
index 9a94fb17139ccfa799ec4f78fad56d7bc1f3a0b9..4341af5913d8b4c46e1d11b3f5f938f430a426f3 100644 (file)
@@ -464,37 +464,6 @@ static int h2_client_new(struct Curl_cfilter *cf,
   return rc;
 }
 
-static ssize_t nw_in_reader(void *reader_ctx,
-                              unsigned char *buf, size_t buflen,
-                              CURLcode *err)
-{
-  struct Curl_cfilter *cf = reader_ctx;
-  struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  size_t nread;
-
-  *err = Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, &nread);
-  return *err ? -1 : (ssize_t)nread;
-}
-
-static ssize_t nw_out_writer(void *writer_ctx,
-                             const unsigned char *buf, size_t buflen,
-                             CURLcode *err)
-{
-  struct Curl_cfilter *cf = writer_ctx;
-  struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  size_t nwritten;
-
-  if(!data) {
-    *err = CURLE_OK;
-    return 0;
-  }
-
-  *err = Curl_conn_cf_send(cf->next, data, (const char *)buf,
-                           buflen, FALSE, &nwritten);
-  CURL_TRC_CF(data, cf, "[0] egress write -> %d, %zu", *err, nwritten);
-  return *err ? -1 : (ssize_t)nwritten;
-}
-
 static ssize_t send_callback(nghttp2_session *h2,
                              const uint8_t *mem, size_t length, int flags,
                              void *userp);
@@ -715,12 +684,12 @@ static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data,
        not in use by any other transfer, there should not be any data here,
        only "protocol frames" */
     CURLcode result;
-    ssize_t nread = -1;
+    size_t nread;
 
     *input_pending = FALSE;
-    nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result);
-    if(nread != -1) {
-      CURL_TRC_CF(data, cf, "%zd bytes stray data read before trying "
+    result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
+    if(!result) {
+      CURL_TRC_CF(data, cf, "%zu bytes stray data read before trying "
                   "h2 connection", nread);
       if(h2_process_pending_input(cf, data, &result) < 0)
         /* immediate error, considered dead */
@@ -773,15 +742,16 @@ static CURLcode nw_out_flush(struct Curl_cfilter *cf,
                              struct Curl_easy *data)
 {
   struct cf_h2_ctx *ctx = cf->ctx;
-  ssize_t nwritten;
+  size_t nwritten;
   CURLcode result;
 
   (void)data;
   if(Curl_bufq_is_empty(&ctx->outbufq))
     return CURLE_OK;
 
-  nwritten = Curl_bufq_pass(&ctx->outbufq, nw_out_writer, cf, &result);
-  if(nwritten < 0) {
+  result = Curl_cf_send_bufq(cf->next, data, &ctx->outbufq, NULL, 0,
+                             &nwritten);
+  if(result) {
     if(result == CURLE_AGAIN) {
       CURL_TRC_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN",
                   Curl_bufq_len(&ctx->outbufq));
@@ -804,7 +774,7 @@ static ssize_t send_callback(nghttp2_session *h2,
   struct Curl_cfilter *cf = userp;
   struct cf_h2_ctx *ctx = cf->ctx;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
-  ssize_t nwritten;
+  size_t nwritten;
   CURLcode result = CURLE_OK;
 
   (void)h2;
@@ -812,11 +782,12 @@ static ssize_t send_callback(nghttp2_session *h2,
   DEBUGASSERT(data);
 
   if(!cf->connected)
-    nwritten = Curl_bufq_write(&ctx->outbufq, buf, blen, &result);
+    result = Curl_bufq_write(&ctx->outbufq, buf, blen, &nwritten);
   else
-    nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen,
-                                    nw_out_writer, cf, &result);
-  if(nwritten < 0) {
+    result = Curl_cf_send_bufq(cf->next, data, &ctx->outbufq, buf, blen,
+                               &nwritten);
+
+  if(result) {
     if(result == CURLE_AGAIN) {
       ctx->nw_out_blocked = 1;
       return NGHTTP2_ERR_WOULDBLOCK;
@@ -829,7 +800,8 @@ static ssize_t send_callback(nghttp2_session *h2,
     ctx->nw_out_blocked = 1;
     return NGHTTP2_ERR_WOULDBLOCK;
   }
-  return nwritten;
+  return (nwritten  > SSIZE_T_MAX) ?
+    NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nwritten;
 }
 
 
@@ -1770,6 +1742,7 @@ static ssize_t req_body_read_callback(nghttp2_session *session,
   struct h2_stream_ctx *stream = NULL;
   CURLcode result;
   ssize_t nread;
+  size_t n;
   (void)source;
 
   (void)cf;
@@ -1788,12 +1761,14 @@ static ssize_t req_body_read_callback(nghttp2_session *session,
   if(!stream)
     return NGHTTP2_ERR_CALLBACK_FAILURE;
 
-  nread = Curl_bufq_read(&stream->sendbuf, buf, length, &result);
-  if(nread < 0) {
+  result = Curl_bufq_read(&stream->sendbuf, buf, length, &n);
+  if(result) {
     if(result != CURLE_AGAIN)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     nread = 0;
   }
+  else
+    nread = (ssize_t)n;
 
   CURL_TRC_CF(data_s, cf, "[%d] req_body_read(len=%zu) eos=%d -> %zd, %d",
               stream_id, length, stream->body_eos, nread, result);
@@ -2056,7 +2031,7 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
   struct cf_h2_ctx *ctx = cf->ctx;
   struct h2_stream_ctx *stream;
   CURLcode result = CURLE_OK;
-  ssize_t nread;
+  size_t nread;
 
   if(should_close_session(ctx)) {
     CURL_TRC_CF(data, cf, "progress ingress, session is closed");
@@ -2086,8 +2061,8 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
       break;
     }
 
-    nread = Curl_bufq_sipn(&ctx->inbufq, 0, nw_in_reader, cf, &result);
-    if(nread < 0) {
+    result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
+    if(result) {
       if(result != CURLE_AGAIN) {
         failf(data, "Failed receiving HTTP2 data: %d(%s)", result,
               curl_easy_strerror(result));
@@ -2101,9 +2076,8 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
       break;
     }
     else {
-      CURL_TRC_CF(data, cf, "[0] ingress: read %zd bytes", nread);
-      data_max_bytes = (data_max_bytes > (size_t)nread) ?
-        (data_max_bytes - (size_t)nread) : 0;
+      CURL_TRC_CF(data, cf, "[0] ingress: read %zu bytes", nread);
+      data_max_bytes = (data_max_bytes > nread) ? (data_max_bytes - nread) : 0;
     }
 
     if(h2_process_pending_input(cf, data, &result))
@@ -2197,7 +2171,7 @@ static ssize_t cf_h2_body_send(struct Curl_cfilter *cf,
                                CURLcode *err)
 {
   struct cf_h2_ctx *ctx = cf->ctx;
-  ssize_t nwritten;
+  size_t nwritten;
 
   if(stream->closed) {
     if(stream->resp_hds_complete) {
@@ -2219,11 +2193,11 @@ static ssize_t cf_h2_body_send(struct Curl_cfilter *cf,
     return -1;
   }
 
-  nwritten = Curl_bufq_write(&stream->sendbuf, buf, blen, err);
-  if(nwritten < 0)
+  *err = Curl_bufq_write(&stream->sendbuf, buf, blen, &nwritten);
+  if(*err)
     return -1;
 
-  if(eos && (blen == (size_t)nwritten))
+  if(eos && (blen == nwritten))
     stream->body_eos = TRUE;
 
   if(eos || !Curl_bufq_is_empty(&stream->sendbuf)) {
@@ -2234,7 +2208,7 @@ static ssize_t cf_h2_body_send(struct Curl_cfilter *cf,
       return -1;
     }
   }
-  return nwritten;
+  return (ssize_t)nwritten;
 }
 
 static CURLcode h2_submit(struct h2_stream_ctx **pstream,
@@ -2971,17 +2945,17 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data,
     /* Remaining data from the protocol switch reply is already using
      * the switched protocol, ie. HTTP/2. We add that to the network
      * inbufq. */
-    ssize_t copied;
+    size_t copied;
 
-    copied = Curl_bufq_write(&ctx->inbufq,
-                             (const unsigned char *)mem, nread, &result);
-    if(copied < 0) {
+    result = Curl_bufq_write(&ctx->inbufq,
+                             (const unsigned char *)mem, nread, &copied);
+    if(result) {
       failf(data, "error on copying HTTP Upgrade response: %d", result);
       return CURLE_RECV_ERROR;
     }
-    if((size_t)copied < nread) {
+    if(copied < nread) {
       failf(data, "connection buffer size could not take all data "
-            "from HTTP Upgrade response header: copied=%zd, datalen=%zu",
+            "from HTTP Upgrade response header: copied=%zu, datalen=%zu",
             copied, nread);
       return CURLE_HTTP2;
     }
index e7c1566296ee17f087efe09917a675a85db49cbe..b186a6ef88e2b31281277e38d10ed24db9c50b38 100644 (file)
@@ -1992,14 +1992,12 @@ static CURLcode cr_mime_read(struct Curl_easy *data,
   }
 
   if(!Curl_bufq_is_empty(&ctx->tmpbuf)) {
-    ssize_t n = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen,
-                               &result);
-    if(n < 0) {
+    result = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen, &nread);
+    if(result) {
       ctx->errored = TRUE;
       ctx->error_result = result;
       return result;
     }
-    nread = (size_t)n;
   }
   else if(blen <= 4) {
     /* Curl_mime_read() may go into an infinite loop when reading
@@ -2009,21 +2007,20 @@ static CURLcode cr_mime_read(struct Curl_easy *data,
     CURL_TRC_READ(data, "cr_mime_read(len=%zu), small read, using tmp", blen);
     nread = Curl_mime_read(tmp, 1, sizeof(tmp), ctx->part);
     if(nread <= sizeof(tmp)) {
-      ssize_t n = Curl_bufq_write(&ctx->tmpbuf, (unsigned char *)tmp, nread,
-                                  &result);
-      if(n < 0) {
+      size_t n;
+      result = Curl_bufq_write(&ctx->tmpbuf, (unsigned char *)tmp, nread, &n);
+      if(result) {
         ctx->errored = TRUE;
         ctx->error_result = result;
         return result;
       }
       /* stored it, read again */
-      n = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen, &result);
-      if(n < 0) {
+      result = Curl_bufq_cread(&ctx->tmpbuf, buf, blen, &nread);
+      if(result) {
         ctx->errored = TRUE;
         ctx->error_result = result;
         return result;
       }
-      nread = (size_t)n;
     }
   }
   else
index d87b3b4e8ec5fce098d8c6f6d88281b01d8a8a14..0d9b23ef0c461df06d222858c13707664acba2ae 100644 (file)
@@ -338,20 +338,18 @@ static CURLcode req_flush(struct Curl_easy *data)
   return CURLE_OK;
 }
 
-static ssize_t add_from_client(void *reader_ctx,
-                               unsigned char *buf, size_t buflen,
-                               CURLcode *err)
+static CURLcode add_from_client(void *reader_ctx,
+                                unsigned char *buf, size_t buflen,
+                                size_t *pnread)
 {
   struct Curl_easy *data = reader_ctx;
-  size_t nread;
+  CURLcode result;
   bool eos;
 
-  *err = Curl_client_read(data, (char *)buf, buflen, &nread, &eos);
-  if(*err)
-    return -1;
-  if(eos)
+  result = Curl_client_read(data, (char *)buf, buflen, pnread, &eos);
+  if(!result && eos)
     data->req.eos_read = TRUE;
-  return (ssize_t)nread;
+  return result;
 }
 
 static CURLcode req_send_buffer_add(struct Curl_easy *data,
@@ -359,13 +357,12 @@ static CURLcode req_send_buffer_add(struct Curl_easy *data,
                                     size_t hds_len)
 {
   CURLcode result = CURLE_OK;
-  ssize_t n;
-  n = Curl_bufq_write(&data->req.sendbuf,
-                      (const unsigned char *)buf, blen, &result);
-  if(n < 0)
+  size_t n;
+  result = Curl_bufq_cwrite(&data->req.sendbuf, buf, blen, &n);
+  if(result)
     return result;
   /* We rely on a SOFTLIMIT on sendbuf, so it can take all data in */
-  DEBUGASSERT((size_t)n == blen);
+  DEBUGASSERT(n == blen);
   data->req.sendbuf_hds_len += hds_len;
   return CURLE_OK;
 }
@@ -437,9 +434,10 @@ CURLcode Curl_req_send_more(struct Curl_easy *data)
      !data->req.eos_read &&
      !Curl_xfer_send_is_paused(data) &&
      !Curl_bufq_is_full(&data->req.sendbuf)) {
-    ssize_t nread = Curl_bufq_sipn(&data->req.sendbuf, 0,
-                                   add_from_client, data, &result);
-    if(nread < 0 && result != CURLE_AGAIN)
+    size_t nread;
+    result = Curl_bufq_sipn(&data->req.sendbuf, 0,
+                            add_from_client, data, &nread);
+    if(result && result != CURLE_AGAIN)
       return result;
   }
 
index a309fa74ffa7cd6d4f3d518cee124d1d4e089d39..2f0c9de8487ce96ca09dfaf097ec45029737f219 100644 (file)
@@ -345,17 +345,16 @@ static CURLcode write_resp_raw(struct Curl_easy *data,
   struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
   CURLcode result = CURLE_OK;
-  ssize_t nwritten;
+  size_t nwritten;
 
   if(!stream)
     return CURLE_RECV_ERROR;
 
-  nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
-  if(nwritten < 0) {
+  result = Curl_bufq_write(&stream->recvbuf, mem, memlen, &nwritten);
+  if(result)
     return result;
-  }
 
-  if((size_t)nwritten < memlen) {
+  if(nwritten < memlen) {
     /* This MUST not happen. Our recbuf is dimensioned to hold the
      * full max_stream_window and then some for this very reason. */
     DEBUGASSERT(0);
@@ -553,7 +552,6 @@ static CURLcode cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
 {
   struct cf_msh3_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  ssize_t nread = -1;
   struct cf_call_data save;
   CURLcode result = CURLE_OK;
 
@@ -572,13 +570,11 @@ static CURLcode cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   }
 
   if(!Curl_bufq_is_empty(&stream->recvbuf)) {
-    nread = Curl_bufq_read(&stream->recvbuf,
-                           (unsigned char *)buf, len, &result);
-    CURL_TRC_CF(data, cf, "read recvbuf(len=%zu) -> %zd, %d",
-                len, nread, result);
-    if(nread < 0)
+    result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread);
+    CURL_TRC_CF(data, cf, "read recvbuf(len=%zu) -> %d, %zu",
+                len, result, *pnread);
+    if(result)
       goto out;
-    *pnread = (size_t)nread;
     if(stream->closed)
       h3_drain_stream(cf, data);
   }
index 320f619c66ebdfb11798569a9b37111db1868fa2..d91cd6b083ca7a2cb11360d22d61a0b45150af08 100644 (file)
@@ -1644,14 +1644,12 @@ static CURLcode cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
     goto out;
   }
   else {
-    ssize_t sent;
-    sent = Curl_bufq_write(&stream->sendbuf, buf, len, &result);
+    result = Curl_bufq_write(&stream->sendbuf, buf, len, pnwritten);
     CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to "
-                "sendbuf(len=%zu) -> %zd, %d",
-                stream->id, len, sent, result);
-    if(sent < 0)
+                "sendbuf(len=%zu) -> %d, %zu",
+                stream->id, len, result, *pnwritten);
+    if(result)
       goto out;
-    *pnwritten = (size_t)sent;
     (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id);
   }
 
@@ -1730,9 +1728,9 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
  * Read a network packet to send from ngtcp2 into `buf`.
  * Return number of bytes written or -1 with *err set.
  */
-static ssize_t read_pkt_to_send(void *userp,
-                                unsigned char *buf, size_t buflen,
-                                CURLcode *err)
+static CURLcode read_pkt_to_send(void *userp,
+                                 unsigned char *buf, size_t buflen,
+                                 size_t *pnread)
 {
   struct pkt_io_ctx *x = userp;
   struct cf_ngtcp2_ctx *ctx = x->cf->ctx;
@@ -1742,7 +1740,9 @@ static ssize_t read_pkt_to_send(void *userp,
   uint32_t flags;
   int64_t stream_id;
   int fin;
-  ssize_t nwritten = 0, n;
+  ssize_t n;
+
+  *pnread = 0;
   veccnt = 0;
   stream_id = -1;
   fin = 0;
@@ -1754,7 +1754,6 @@ static ssize_t read_pkt_to_send(void *userp,
    * When ngtcp2 is happy (because it has no other frame that would fit
    * or it has nothing more to send), it returns the total length
    * of the assembled packet. This may be 0 if there was nothing to send. */
-  *err = CURLE_OK;
   for(;;) {
 
     if(ctx->h3conn && ngtcp2_conn_get_max_data_left(ctx->qconn)) {
@@ -1764,8 +1763,7 @@ static ssize_t read_pkt_to_send(void *userp,
         failf(x->data, "nghttp3_conn_writev_stream returned error: %s",
               nghttp3_strerror((int)veccnt));
         cf_ngtcp2_h3_err_set(x->cf, x->data, (int)veccnt);
-        *err = CURLE_SEND_ERROR;
-        return -1;
+        return CURLE_SEND_ERROR;
       }
     }
 
@@ -1777,9 +1775,7 @@ static ssize_t read_pkt_to_send(void *userp,
                                   (const ngtcp2_vec *)vec, veccnt, x->ts);
     if(n == 0) {
       /* nothing to send */
-      *err = CURLE_AGAIN;
-      nwritten = -1;
-      goto out;
+      return CURLE_AGAIN;
     }
     else if(n < 0) {
       switch(n) {
@@ -1811,9 +1807,7 @@ static ssize_t read_pkt_to_send(void *userp,
         failf(x->data, "ngtcp2_conn_writev_stream returned error: %s",
               ngtcp2_strerror((int)n));
         cf_ngtcp2_err_set(x->cf, x->data, (int)n);
-        *err = CURLE_SEND_ERROR;
-        nwritten = -1;
-        goto out;
+        return CURLE_SEND_ERROR;
       }
     }
 
@@ -1829,12 +1823,10 @@ static ssize_t read_pkt_to_send(void *userp,
 
     if(n > 0) {
       /* packet assembled, leave */
-      nwritten = n;
-      goto out;
+      *pnread = (size_t)n;
+      return CURLE_OK;
     }
   }
-out:
-  return nwritten;
 }
 
 static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
@@ -1842,7 +1834,7 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
                                    struct pkt_io_ctx *pktx)
 {
   struct cf_ngtcp2_ctx *ctx = cf->ctx;
-  ssize_t nread;
+  size_t nread;
   size_t max_payload_size, path_max_payload_size, max_pktcnt;
   size_t pktcnt = 0;
   size_t gsolen = 0;  /* this disables gso until we have a clue */
@@ -1887,9 +1879,9 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
 
   for(;;) {
     /* add the next packet to send, if any, to our buffer */
-    nread = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size,
-                           read_pkt_to_send, pktx, &curlcode);
-    if(nread < 0) {
+    curlcode = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size,
+                              read_pkt_to_send, pktx, &nread);
+    if(curlcode) {
       if(curlcode != CURLE_AGAIN)
         return curlcode;
       /* Nothing more to add, flush and leave */
@@ -1908,10 +1900,10 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
     if(pktcnt == 0) {
       /* first packet in buffer. This is either of a known, "good"
        * payload size or it is a PMTUD. We will see. */
-      gsolen = (size_t)nread;
+      gsolen = nread;
     }
-    else if((size_t)nread > gsolen ||
-            (gsolen > path_max_payload_size && (size_t)nread != gsolen)) {
+    else if(nread > gsolen ||
+            (gsolen > path_max_payload_size && nread != gsolen)) {
       /* The just added packet is a PMTUD *or* the one(s) before the
        * just added were PMTUD and the last one is smaller.
        * Flush the buffer before the last add. */
@@ -1928,7 +1920,7 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
       continue;
     }
 
-    if(++pktcnt >= max_pktcnt || (size_t)nread < gsolen) {
+    if(++pktcnt >= max_pktcnt || nread < gsolen) {
       /* Reached MAX_PKT_BURST *or*
        * the capacity of our buffer *or*
        * last add was shorter than the previous ones, flush */
@@ -2102,8 +2094,9 @@ static CURLcode cf_ngtcp2_shutdown(struct Curl_cfilter *cf,
       /* Ignore amount written. sendbuf was empty and has always room for
        * NGTCP2_MAX_UDP_PAYLOAD_SIZE. It can only completely fail, in which
        * case `result` is set non zero. */
-      (void)Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer,
-                            (size_t)nwritten, &result);
+      size_t n;
+      result = Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer,
+                               (size_t)nwritten, &n);
       if(result) {
         CURL_TRC_CF(data, cf, "error %d adding shutdown packets to sendbuf, "
                     "aborting shutdown", result);
index 484ab61865b21cfce5900501f33c83fa74a2cf86..e68850c609f547eb628b77e11652265b223eb632 100644 (file)
@@ -766,21 +766,20 @@ static CURLcode write_resp_raw(struct Curl_cfilter *cf,
   struct cf_osslq_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
   CURLcode result = CURLE_OK;
-  ssize_t nwritten;
+  size_t nwritten;
 
   (void)cf;
   if(!stream) {
     return CURLE_RECV_ERROR;
   }
-  nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
-  if(nwritten < 0) {
+  result = Curl_bufq_write(&stream->recvbuf, mem, memlen, &nwritten);
+  if(result)
     return result;
-  }
 
   if(!flow)
     stream->recv_buf_nonflow += (size_t)nwritten;
 
-  if((size_t)nwritten < memlen) {
+  if(nwritten < memlen) {
     /* This MUST not happen. Our recbuf is dimensioned to hold the
      * full max_stream_window and then some for this very reason. */
     DEBUGASSERT(0);
@@ -1242,27 +1241,24 @@ struct h3_quic_recv_ctx {
   struct cf_osslq_stream *s;
 };
 
-static ssize_t h3_quic_recv(void *reader_ctx,
+static CURLcode h3_quic_recv(void *reader_ctx,
                             unsigned char *buf, size_t len,
-                            CURLcode *err)
+                            size_t *pnread)
 {
   struct h3_quic_recv_ctx *x = reader_ctx;
-  size_t nread;
   int rv;
 
-  *err = CURLE_OK;
-  rv = SSL_read_ex(x->s->ssl, buf, len, &nread);
+  rv = SSL_read_ex(x->s->ssl, buf, len, pnread);
   if(rv <= 0) {
     int detail = SSL_get_error(x->s->ssl, rv);
     if(detail == SSL_ERROR_WANT_READ || detail == SSL_ERROR_WANT_WRITE) {
-      *err = CURLE_AGAIN;
-      return -1;
+      return CURLE_AGAIN;
     }
     else if(detail == SSL_ERROR_ZERO_RETURN) {
       CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] h3_quic_recv -> EOS",
                   x->s->id);
       x->s->recvd_eos = TRUE;
-      return 0;
+      return CURLE_OK;
     }
     else if(SSL_get_stream_read_state(x->s->ssl) ==
             SSL_STREAM_STATE_RESET_REMOTE) {
@@ -1275,14 +1271,13 @@ static ssize_t h3_quic_recv(void *reader_ctx,
         x->s->reset = TRUE;
       }
       x->s->recvd_eos = TRUE;
-      return 0;
+      return CURLE_OK;
     }
     else {
-      *err = cf_osslq_ssl_err(x->cf, x->data, detail, CURLE_RECV_ERROR);
-      return -1;
+      return cf_osslq_ssl_err(x->cf, x->data, detail, CURLE_RECV_ERROR);
     }
   }
-  return (ssize_t)nread;
+  return CURLE_OK;
 }
 
 static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
@@ -1292,6 +1287,7 @@ static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
   struct cf_osslq_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
   ssize_t nread;
+  size_t n;
   struct h3_quic_recv_ctx x;
   bool eagain = FALSE;
   size_t total_recv_len = 0;
@@ -1307,8 +1303,8 @@ static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
         (total_recv_len < H3_STREAM_CHUNK_SIZE)) {
     if(Curl_bufq_is_empty(&s->recvbuf) && !s->recvd_eos) {
       while(!eagain && !s->recvd_eos && !Curl_bufq_is_full(&s->recvbuf)) {
-        nread = Curl_bufq_sipn(&s->recvbuf, 0, h3_quic_recv, &x, &result);
-        if(nread < 0) {
+        result = Curl_bufq_sipn(&s->recvbuf, 0, h3_quic_recv, &x, &n);
+        if(result) {
           if(result != CURLE_AGAIN)
             goto out;
           result = CURLE_OK;
@@ -2045,14 +2041,12 @@ static CURLcode cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
     goto out;
   }
   else {
-    nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, &result);
+    result = Curl_bufq_write(&stream->sendbuf, buf, len, pnwritten);
     CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to "
-                "sendbuf(len=%zu) -> %zd, %d",
-                stream->s.id, len, nwritten, result);
-    if(nwritten < 0) {
+                "sendbuf(len=%zu) -> %d, %zu",
+                stream->s.id, len, result, *pnwritten);
+    if(result)
       goto out;
-    }
-    *pnwritten = (size_t)nwritten;
     (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id);
   }
 
@@ -2099,7 +2093,6 @@ static CURLcode cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
 {
   struct cf_osslq_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  ssize_t nread = -1;
   struct cf_call_data save;
   CURLcode result = CURLE_OK, r2;
 
@@ -2117,14 +2110,12 @@ static CURLcode cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   }
 
   if(!Curl_bufq_is_empty(&stream->recvbuf)) {
-    nread = Curl_bufq_read(&stream->recvbuf,
-                           (unsigned char *)buf, len, &result);
-    if(nread < 0) {
+    result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread);
+    if(result) {
       CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read recvbuf(len=%zu) "
-                  "-> %zd, %d", stream->s.id, len, nread, result);
+                  "-> %d, %zu", stream->s.id, len, result, *pnread);
       goto out;
     }
-    *pnread = (size_t)nread;
   }
 
   r2 = cf_progress_ingress(cf, data);
@@ -2135,14 +2126,12 @@ static CURLcode cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
 
   /* recvbuf had nothing before, maybe after progressing ingress? */
   if(!*pnread && !Curl_bufq_is_empty(&stream->recvbuf)) {
-    nread = Curl_bufq_read(&stream->recvbuf,
-                           (unsigned char *)buf, len, &result);
-    if(nread < 0) {
+    result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread);
+    if(result) {
       CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read recvbuf(len=%zu) "
-                  "-> %zd, %d", stream->s.id, len, nread, result);
+                  "-> %d, %zu", stream->s.id, len, result, *pnread);
       goto out;
     }
-    *pnread = (size_t)nread;
   }
 
   if(*pnread) {
index 33d295b836a2e8cd1cdcb8ed8dac1d193a61a1bb..57152e2ee2ad7fde3042c8308f76564de5bc18e2 100644 (file)
@@ -327,16 +327,16 @@ static CURLcode write_resp_raw(struct Curl_cfilter *cf,
   struct cf_quiche_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
   CURLcode result = CURLE_OK;
-  ssize_t nwritten;
+  size_t nwritten;
 
   (void)cf;
   if(!stream)
     return CURLE_RECV_ERROR;
-  nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
-  if(nwritten < 0)
+  result = Curl_bufq_write(&stream->recvbuf, mem, memlen, &nwritten);
+  if(result)
     return result;
 
-  if((size_t)nwritten < memlen) {
+  if(nwritten < memlen) {
     /* This MUST not happen. Our recbuf is dimensioned to hold the
      * full max_stream_window and then some for this very reason. */
     DEBUGASSERT(0);
@@ -390,30 +390,26 @@ static int cb_each_header(uint8_t *name, size_t name_len,
   return result;
 }
 
-static ssize_t stream_resp_read(void *reader_ctx,
-                                unsigned char *buf, size_t len,
-                                CURLcode *err)
+static CURLcode stream_resp_read(void *reader_ctx,
+                                 unsigned char *buf, size_t len,
+                                 size_t *pnread)
 {
   struct cb_ctx *x = reader_ctx;
   struct cf_quiche_ctx *ctx = x->cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
   ssize_t nread;
 
-  if(!stream) {
-    *err = CURLE_RECV_ERROR;
-    return -1;
-  }
+  *pnread = 0;
+  if(!stream)
+    return CURLE_RECV_ERROR;
 
-  nread = quiche_h3_recv_body(ctx->h3c, ctx->qconn, stream->id,
-                              buf, len);
+  nread = quiche_h3_recv_body(ctx->h3c, ctx->qconn, stream->id, buf, len);
   if(nread >= 0) {
-    *err = CURLE_OK;
-    return nread;
-  }
-  else {
-    *err = CURLE_AGAIN;
-    return -1;
+    *pnread = (size_t)nread;
+    return CURLE_OK;
   }
+  else
+    return CURLE_AGAIN;
 }
 
 static CURLcode cf_recv_body(struct Curl_cfilter *cf,
@@ -421,7 +417,7 @@ static CURLcode cf_recv_body(struct Curl_cfilter *cf,
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  ssize_t nwritten;
+  size_t nread;
   struct cb_ctx cb_ctx;
   CURLcode result = CURLE_OK;
 
@@ -437,12 +433,12 @@ static CURLcode cf_recv_body(struct Curl_cfilter *cf,
 
   cb_ctx.cf = cf;
   cb_ctx.data = data;
-  nwritten = Curl_bufq_slurp(&stream->recvbuf,
-                             stream_resp_read, &cb_ctx, &result);
+  result = Curl_bufq_slurp(&stream->recvbuf,
+                           stream_resp_read, &cb_ctx, &nread);
 
-  if(nwritten < 0 && result != CURLE_AGAIN) {
-    CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] recv_body error %zd",
-                stream->id, nwritten);
+  if(result && result != CURLE_AGAIN) {
+    CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] recv_body error %zu",
+                stream->id, nread);
     failf(data, "Error %d in HTTP/3 response body for stream[%"FMT_PRIu64"]",
           result, stream->id);
     stream->closed = TRUE;
@@ -714,27 +710,25 @@ struct read_ctx {
   quiche_send_info send_info;
 };
 
-static ssize_t read_pkt_to_send(void *userp,
-                                unsigned char *buf, size_t buflen,
-                                CURLcode *err)
+static CURLcode read_pkt_to_send(void *userp,
+                                 unsigned char *buf, size_t buflen,
+                                 size_t *pnread)
 {
   struct read_ctx *x = userp;
   struct cf_quiche_ctx *ctx = x->cf->ctx;
-  ssize_t nwritten;
+  ssize_t n;
 
-  nwritten = quiche_conn_send(ctx->qconn, buf, buflen, &x->send_info);
-  if(nwritten == QUICHE_ERR_DONE) {
-    *err = CURLE_AGAIN;
-    return -1;
-  }
+  *pnread = 0;
+  n = quiche_conn_send(ctx->qconn, buf, buflen, &x->send_info);
+  if(n == QUICHE_ERR_DONE)
+    return CURLE_AGAIN;
 
-  if(nwritten < 0) {
-    failf(x->data, "quiche_conn_send returned %zd", nwritten);
-    *err = CURLE_SEND_ERROR;
-    return -1;
+  if(n < 0) {
+    failf(x->data, "quiche_conn_send returned %zd", n);
+    return CURLE_SEND_ERROR;
   }
-  *err = CURLE_OK;
-  return nwritten;
+  *pnread = (size_t)n;
+  return CURLE_OK;
 }
 
 /*
@@ -745,7 +739,7 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
                                 struct Curl_easy *data)
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
-  ssize_t nread;
+  size_t nread;
   CURLcode result;
   curl_int64_t expiry_ns;
   curl_int64_t timeout_ns;
@@ -783,9 +777,9 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
   gsolen = quiche_conn_max_send_udp_payload_size(ctx->qconn);
   for(;;) {
     /* add the next packet to send, if any, to our buffer */
-    nread = Curl_bufq_sipn(&ctx->q.sendbuf, 0,
-                           read_pkt_to_send, &readx, &result);
-    if(nread < 0) {
+    result = Curl_bufq_sipn(&ctx->q.sendbuf, 0,
+                            read_pkt_to_send, &readx, &nread);
+    if(result) {
       if(result != CURLE_AGAIN)
         return result;
       /* Nothing more to add, flush and leave */
@@ -801,7 +795,7 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
     }
 
     ++pkt_count;
-    if((size_t)nread < gsolen || pkt_count >= MAX_PKT_BURST) {
+    if(nread < gsolen || pkt_count >= MAX_PKT_BURST) {
       result = vquic_send(cf, data, &ctx->q, gsolen);
       if(result) {
         if(result == CURLE_AGAIN) {
@@ -823,37 +817,31 @@ out:
   return result;
 }
 
-static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
+static CURLcode recv_closed_stream(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
-                                  CURLcode *err)
+                                  size_t *pnread)
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  ssize_t nread = -1;
+  CURLcode result = CURLE_OK;
 
   DEBUGASSERT(stream);
+  *pnread = 0;
   if(stream->reset) {
     failf(data,
           "HTTP/3 stream %" FMT_PRIu64 " reset by server", stream->id);
-    *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+    result = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
     CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, was reset -> %d",
-                stream->id, *err);
+                stream->id, result);
   }
   else if(!stream->resp_got_header) {
     failf(data,
           "HTTP/3 stream %" FMT_PRIu64 " was closed cleanly, but before "
           "getting all response header fields, treated as error",
           stream->id);
-    /* *err = CURLE_PARTIAL_FILE; */
-    *err = CURLE_HTTP3;
-    CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, closed incomplete"
-                " -> %d", stream->id, *err);
-  }
-  else {
-    *err = CURLE_OK;
-    nread = 0;
+    result = CURLE_HTTP3;
   }
-  return nread;
+  return result;
 }
 
 static CURLcode cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -861,7 +849,6 @@ static CURLcode cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
   struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-  ssize_t nread = -1;
   CURLcode result = CURLE_OK, r2;
 
   *pnread = 0;
@@ -872,13 +859,11 @@ static CURLcode cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
 
 
   if(!Curl_bufq_is_empty(&stream->recvbuf)) {
-    nread = Curl_bufq_read(&stream->recvbuf,
-                           (unsigned char *)buf, len, &result);
+    result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread);
     CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] read recvbuf(len=%zu) "
-                "-> %zd, %d", stream->id, len, nread, result);
-    if(nread < 0)
+                "-> %d, %zu", stream->id, len, result, *pnread);
+    if(result)
       goto out;
-    *pnread = (size_t)nread;
   }
 
   if(cf_process_ingress(cf, data)) {
@@ -888,14 +873,12 @@ static CURLcode cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   }
 
   /* recvbuf had nothing before, maybe after progressing ingress? */
-  if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) {
-    nread = Curl_bufq_read(&stream->recvbuf,
-                           (unsigned char *)buf, len, &result);
+  if(!*pnread && !Curl_bufq_is_empty(&stream->recvbuf)) {
+    result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread);
     CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] read recvbuf(len=%zu) "
-                "-> %zd, %d", stream->id, len, nread, result);
-    if(nread < 0)
+                "-> %d, %zu", stream->id, len, result, *pnread);
+    if(result)
       goto out;
-    *pnread = (size_t)nread;
   }
 
   if(*pnread) {
@@ -903,16 +886,14 @@ static CURLcode cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
       Curl_multi_mark_dirty(data);
   }
   else {
-    if(stream->closed) {
-      nread = recv_closed_stream(cf, data, &result);
-      goto out;
-    }
+    if(stream->closed)
+      result = recv_closed_stream(cf, data, pnread);
     else if(quiche_conn_is_draining(ctx->qconn)) {
       failf(data, "QUIC connection is draining");
       result = CURLE_HTTP3;
-      goto out;
     }
-    result = CURLE_AGAIN;
+    else
+      result = CURLE_AGAIN;
   }
 
 out:
@@ -922,7 +903,7 @@ out:
     result = r2;
   }
   if(*pnread > 0)
-    ctx->data_recvd += nread;
+    ctx->data_recvd += *pnread;
   CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] cf_recv(total=%"
               FMT_OFF_T ") -> %d, %zu",
               stream->id, ctx->data_recvd, result, *pnread);
index 43f251a0a97acdfcd0f9f07376e59444a1db309f..f34c29287b15add37e74b59e8f8b8a0933a0a3c8 100644 (file)
@@ -1346,7 +1346,7 @@ static CURLcode ssl_cf_set_earlydata(struct Curl_cfilter *cf,
                                      const void *buf, size_t blen)
 {
   struct ssl_connect_data *connssl = cf->ctx;
-  ssize_t nwritten = 0;
+  size_t nwritten = 0;
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_await);
@@ -1354,10 +1354,10 @@ static CURLcode ssl_cf_set_earlydata(struct Curl_cfilter *cf,
   if(blen) {
     if(blen > connssl->earlydata_max)
       blen = connssl->earlydata_max;
-    nwritten = Curl_bufq_write(&connssl->earlydata, buf, blen, &result);
+    result = Curl_bufq_write(&connssl->earlydata, buf, blen, &nwritten);
     CURL_TRC_CF(data, cf, "ssl_cf_set_earlydata(len=%zu) -> %zd",
                 blen, nwritten);
-    if(nwritten < 0)
+    if(result)
       return result;
   }
   return CURLE_OK;
index fc02025f1d23acc41d0fe249a140aa81aa81a7dd..aa313b356cb7e6d1990e765c6cc4180b03d839cc 100644 (file)
--- a/lib/ws.c
+++ b/lib/ws.c
@@ -653,11 +653,11 @@ static CURLcode ws_cw_write(struct Curl_easy *data,
   }
 
   if(nbytes) {
-    ssize_t nwritten;
-    nwritten = Curl_bufq_write(&ctx->buf, (const unsigned char *)buf,
-                               nbytes, &result);
-    if(nwritten < 0) {
-      infof(data, "[WS] error adding data to buffer %d", result);
+    size_t nwritten;
+    result = Curl_bufq_write(&ctx->buf, (const unsigned char *)buf,
+                             nbytes, &nwritten);
+    if(result) {
+      infof(data, "WS: error adding data to buffer %d", result);
       return result;
     }
   }
@@ -756,8 +756,7 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data,
 {
   unsigned char firstbyte = 0;
   unsigned char head[14];
-  size_t hlen;
-  ssize_t n;
+  size_t hlen, n;
 
   if(payload_len < 0) {
     failf(data, "[WS] starting new frame with negative payload length %"
@@ -837,16 +836,16 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data,
   /* reset for payload to come */
   enc->xori = 0;
 
-  n = Curl_bufq_write(out, head, hlen, err);
-  if(n < 0)
+  *err = Curl_bufq_write(out, head, hlen, &n);
+  if(*err)
     return -1;
-  if((size_t)n != hlen) {
+  if(n != hlen) {
     /* We use a bufq with SOFT_LIMIT, writing should always succeed */
     DEBUGASSERT(0);
     *err = CURLE_SEND_ERROR;
     return -1;
   }
-  return n;
+  return (ssize_t)n;
 }
 
 static ssize_t ws_enc_write_payload(struct ws_encoder *enc,
@@ -854,8 +853,7 @@ static ssize_t ws_enc_write_payload(struct ws_encoder *enc,
                                     const unsigned char *buf, size_t buflen,
                                     struct bufq *out, CURLcode *err)
 {
-  ssize_t n;
-  size_t i, len;
+  size_t i, len, n;
 
   if(Curl_bufq_is_full(out)) {
     *err = CURLE_AGAIN;
@@ -869,8 +867,8 @@ static ssize_t ws_enc_write_payload(struct ws_encoder *enc,
 
   for(i = 0; i < len; ++i) {
     unsigned char c = buf[i] ^ enc->mask[enc->xori];
-    n = Curl_bufq_write(out, &c, 1, err);
-    if(n < 0) {
+    *err = Curl_bufq_write(out, &c, 1, &n);
+    if(*err) {
       if((*err != CURLE_AGAIN) || !i)
         return -1;
       break;
@@ -1054,15 +1052,16 @@ CURLcode Curl_ws_accept(struct Curl_easy *data,
   }
 
   if(data->set.connect_only) {
-    ssize_t nwritten;
+    size_t nwritten;
     /* In CONNECT_ONLY setup, the payloads from `mem` need to be received
      * when using `curl_ws_recv` later on after this transfer is already
      * marked as DONE. */
-    nwritten = Curl_bufq_write(&ws->recvbuf, (const unsigned char *)mem,
-                               nread, &result);
-    if(nwritten < 0)
+    result = Curl_bufq_write(&ws->recvbuf, (const unsigned char *)mem,
+                             nread, &nwritten);
+    if(result)
       return result;
-    CURL_TRC_WS(data, "%zu bytes payload", nread);
+    DEBUGASSERT(nread == nwritten);
+    infof(data, "%zu bytes websocket payload", nread);
   }
   else { /* !connect_only */
     /* And pass any additional data to the writers */
@@ -1137,17 +1136,12 @@ static ssize_t ws_client_collect(const unsigned char *buf, size_t buflen,
   return nwritten;
 }
 
-static ssize_t nw_in_recv(void *reader_ctx,
-                          unsigned char *buf, size_t buflen,
-                          CURLcode *err)
+static CURLcode nw_in_recv(void *reader_ctx,
+                           unsigned char *buf, size_t buflen,
+                           size_t *pnread)
 {
   struct Curl_easy *data = reader_ctx;
-  size_t nread;
-
-  *err = curl_easy_recv(data, buf, buflen, &nread);
-  if(*err)
-    return -1;
-  return (ssize_t)nread;
+  return curl_easy_recv(data, buf, buflen, pnread);
 }
 
 CURL_EXTERN CURLcode curl_ws_recv(CURL *d, void *buffer,
@@ -1192,10 +1186,10 @@ CURL_EXTERN CURLcode curl_ws_recv(CURL *d, void *buffer,
 
     /* receive more when our buffer is empty */
     if(Curl_bufq_is_empty(&ws->recvbuf)) {
-      ssize_t n = Curl_bufq_slurp(&ws->recvbuf, nw_in_recv, data, &result);
-      if(n < 0) {
+      size_t n;
+      result = Curl_bufq_slurp(&ws->recvbuf, nw_in_recv, data, &n);
+      if(result)
         return result;
-      }
       else if(n == 0) {
         /* connection closed */
         infof(data, "[WS] connection expectedly closed?");
index 8dd79d2d97742e60bf554b6b1a56c111fb423db0..7d7fdd777920f7cb4d88363f85679917c5ef1133 100644 (file)
@@ -86,7 +86,8 @@ static void check_bufq(size_t pool_spares,
   struct bufc_pool pool;
   size_t max_len = chunk_size * max_chunks;
   CURLcode result;
-  ssize_t n, i;
+  ssize_t i;
+  size_t n2;
   size_t nwritten, nread;
 
   if(pool_spares > 0) {
@@ -104,18 +105,17 @@ static void check_bufq(size_t pool_spares,
   fail_unless(q.spare == NULL, "init: spare not NULL");
   fail_unless(Curl_bufq_len(&q) == 0, "init: bufq length != 0");
 
-  n = Curl_bufq_write(&q, test_data, wsize, &result);
-  fail_unless(n >= 0, "write: negative size returned");
-  fail_unless((size_t)n <= wsize, "write: wrong size returned");
+  result = Curl_bufq_write(&q, test_data, wsize, &n2);
+  fail_unless(n2 <= wsize, "write: wrong size returned");
   fail_unless(result == CURLE_OK, "write: wrong result returned");
 
   /* write empty bufq full */
   nwritten = 0;
   Curl_bufq_reset(&q);
   while(!Curl_bufq_is_full(&q)) {
-    n = Curl_bufq_write(&q, test_data, wsize, &result);
-    if(n >= 0) {
-      nwritten += (size_t)n;
+    result = Curl_bufq_write(&q, test_data, wsize, &n2);
+    if(!result) {
+      nwritten += n2;
     }
     else if(result != CURLE_AGAIN) {
       fail_unless(result == CURLE_AGAIN, "write-loop: unexpected result");
@@ -132,9 +132,9 @@ static void check_bufq(size_t pool_spares,
   /* read full bufq empty */
   nread = 0;
   while(!Curl_bufq_is_empty(&q)) {
-    n = Curl_bufq_read(&q, test_data, rsize, &result);
-    if(n >= 0) {
-      nread += (size_t)n;
+    result = Curl_bufq_read(&q, test_data, rsize, &n2);
+    if(!result) {
+      nread += n2;
     }
     else if(result != CURLE_AGAIN) {
       fail_unless(result == CURLE_AGAIN, "read-loop: unexpected result");
@@ -153,13 +153,13 @@ static void check_bufq(size_t pool_spares,
   }
 
   for(i = 0; i < 1000; ++i) {
-    n = Curl_bufq_write(&q, test_data, wsize, &result);
-    if(n < 0 && result != CURLE_AGAIN) {
+    result = Curl_bufq_write(&q, test_data, wsize, &n2);
+    if(result && result != CURLE_AGAIN) {
       fail_unless(result == CURLE_AGAIN, "rw-loop: unexpected write result");
       break;
     }
-    n = Curl_bufq_read(&q, test_data, rsize, &result);
-    if(n < 0 && result != CURLE_AGAIN) {
+    result = Curl_bufq_read(&q, test_data, rsize, &n2);
+    if(result && result != CURLE_AGAIN) {
       fail_unless(result == CURLE_AGAIN, "rw-loop: unexpected read result");
       break;
     }
@@ -170,12 +170,12 @@ static void check_bufq(size_t pool_spares,
   Curl_bufq_init2(&q, chunk_size, max_chunks, (opts|BUFQ_OPT_SOFT_LIMIT));
   nwritten = 0;
   while(!Curl_bufq_is_full(&q)) {
-    n = Curl_bufq_write(&q, test_data, wsize, &result);
-    if(n < 0 || (size_t)n != wsize) {
-      fail_unless(n > 0 && (size_t)n == wsize, "write should be complete");
+    result = Curl_bufq_write(&q, test_data, wsize, &n2);
+    if(result || n2 != wsize) {
+      fail_unless(!result && n2 == wsize, "write should be complete");
       break;
     }
-    nwritten += (size_t)n;
+    nwritten += n2;
   }
   if(nwritten < max_len) {
     curl_mfprintf(stderr, "%zu bytes written, but max_len=%zu\n",
@@ -184,18 +184,18 @@ static void check_bufq(size_t pool_spares,
     fail_if(TRUE, "write: bufq full but nwritten wrong");
   }
   /* do one more write on a full bufq, should work */
-  n = Curl_bufq_write(&q, test_data, wsize, &result);
-  fail_unless(n > 0 && (size_t)n == wsize, "write should be complete");
-  nwritten += (size_t)n;
+  result = Curl_bufq_write(&q, test_data, wsize, &n2);
+  fail_unless(!result && n2 == wsize, "write should be complete");
+  nwritten += n2;
   /* see that we get all out again */
   nread = 0;
   while(!Curl_bufq_is_empty(&q)) {
-    n = Curl_bufq_read(&q, test_data, rsize, &result);
-    if(n <= 0) {
-      fail_unless(n > 0, "read-loop: unexpected fail");
+    result = Curl_bufq_read(&q, test_data, rsize, &n2);
+    if(result) {
+      fail_unless(result, "read-loop: unexpected fail");
       break;
     }
-    nread += (size_t)n;
+    nread += n2;
   }
   fail_unless(nread == nwritten, "did not get the same out as put in");
 
@@ -210,13 +210,13 @@ static CURLcode test_unit2601(char *arg)
   UNITTEST_BEGIN_SIMPLE
 
   struct bufq q;
-  ssize_t n;
+  size_t n;
   CURLcode result;
   unsigned char buf[16*1024];
 
   Curl_bufq_init(&q, 8*1024, 12);
-  n = Curl_bufq_read(&q, buf, 128, &result);
-  fail_unless(n < 0 && result == CURLE_AGAIN, "read empty fail");
+  result = Curl_bufq_read(&q, buf, 128, &n);
+  fail_unless(result && result == CURLE_AGAIN, "read empty fail");
   Curl_bufq_free(&q);
 
   check_bufq(0, 1024, 4, 128, 128, BUFQ_OPT_NONE);