]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: channel: functions to get data from a buffer without copy
authorThierry FOURNIER <tfournier@haproxy.com>
Mon, 16 Feb 2015 18:26:48 +0000 (19:26 +0100)
committerWilly Tarreau <w@1wt.eu>
Sat, 28 Feb 2015 22:12:33 +0000 (23:12 +0100)
We now have functions to retrieve one block and one line from
either the input or the output part of a buffer. They return
up to two (pointer,length) values in case the buffer wraps.

include/proto/channel.h
src/channel.c

index da47c166bcbb75670a590045cbdadbaa60a7cb32..f6b046991df7f1455392e52330694087f64c5b35 100644 (file)
@@ -46,9 +46,14 @@ unsigned long long __channel_forward(struct channel *chn, unsigned long long byt
 int bi_putblk(struct channel *chn, const char *str, int len);
 struct buffer *bi_swpbuf(struct channel *chn, struct buffer *buf);
 int bi_putchr(struct channel *chn, char c);
+int bi_getline_nc(struct channel *chn, char **blk1, int *len1, char **blk2, int *len2);
+int bi_getblk_nc(struct channel *chn, char **blk1, int *len1, char **blk2, int *len2);
 int bo_inject(struct channel *chn, const char *msg, int len);
 int bo_getline(struct channel *chn, char *str, int len);
 int bo_getblk(struct channel *chn, char *blk, int len, int offset);
+int bo_getline_nc(struct channel *chn, char **blk1, int *len1, char **blk2, int *len2);
+int bo_getblk_nc(struct channel *chn, char **blk1, int *len1, char **blk2, int *len2);
+
 
 /* Initialize all fields in the channel. */
 static inline void channel_init(struct channel *chn)
index 177ab5a88d02ff9bf27152cc18273562d8781feb..4e0a2ac6c222b1198ef5aa776e9a29d66bc37aac 100644 (file)
@@ -329,6 +329,157 @@ int bo_getblk(struct channel *chn, char *blk, int len, int offset)
        return len;
 }
 
+/* Gets one or two blocks of data at once from a channel's output buffer.
+ * Return values :
+ *   >0 : number of blocks filled (1 or 2). blk1 is always filled before blk2.
+ *   =0 : not enough data available. <blk*> are left undefined.
+ *   <0 : no more bytes readable because output is shut.
+ * The channel status is not changed. The caller must call bo_skip() to
+ * update it. Unused buffers are left in an undefined state.
+ */
+int bo_getblk_nc(struct channel *chn, char **blk1, int *len1, char **blk2, int *len2)
+{
+       if (unlikely(chn->buf->o == 0)) {
+               if (chn->flags & CF_SHUTW)
+                       return -1;
+               return 0;
+       }
+
+       if (unlikely(chn->buf->p - chn->buf->o < chn->buf->data)) {
+               *blk1 = chn->buf->p - chn->buf->o + chn->buf->size;
+               *len1 = chn->buf->data + chn->buf->size - *blk1;
+               *blk2 = chn->buf->data;
+               *len2 = chn->buf->p - chn->buf->data;
+               return 2;
+       }
+
+       *blk1 = chn->buf->p - chn->buf->o;
+       *len1 = chn->buf->o;
+       return 1;
+}
+
+/* Gets one text line out of a channel's output buffer from a stream interface.
+ * Return values :
+ *   >0 : number of blocks returned (1 or 2). blk1 is always filled before blk2.
+ *   =0 : not enough data available.
+ *   <0 : no more bytes readable because output is shut.
+ * The '\n' is waited for as long as neither the buffer nor the output are
+ * full. If either of them is full, the string may be returned as is, without
+ * the '\n'. Unused buffers are left in an undefined state.
+ */
+int bo_getline_nc(struct channel *chn,
+                  char **blk1, int *len1,
+                  char **blk2, int *len2)
+{
+       int retcode;
+       int l;
+
+       retcode = bo_getblk_nc(chn, blk1, len1, blk2, len2);
+       if (unlikely(retcode) <= 0)
+               return retcode;
+
+       for (l = 0; l < *len1 && (*blk1)[l] != '\n'; l++);
+       if (l < *len1 && (*blk1)[l] == '\n') {
+               *len1 = l + 1;
+               return 1;
+       }
+
+       if (retcode >= 2) {
+               for (l = 0; l < *len2 && (*blk2)[l] != '\n'; l++);
+               if (l < *len2 && (*blk2)[l] == '\n') {
+                       *len2 = l + 1;
+                       return 2;
+               }
+       }
+
+       if (chn->flags & CF_SHUTW) {
+               /* If we have found no LF and the buffer is shut, then
+                * the resulting string is made of the concatenation of
+                * the pending blocks (1 or 2).
+                */
+               return retcode;
+       }
+
+       /* No LF yet and not shut yet */
+       return 0;
+}
+
+/* Gets one full block of data at once from a channel's input buffer.
+ * This function can return the data slitted in one or two blocks.
+ * Return values :
+ *   >0 : number of blocks returned (1 or 2). blk1 is always filled before blk2.
+ *   =0 : not enough data available.
+ *   <0 : no more bytes readable because input is shut.
+ */
+int bi_getblk_nc(struct channel *chn,
+                 char **blk1, int *len1,
+                 char **blk2, int *len2)
+{
+       if (unlikely(chn->buf->i == 0)) {
+               if (chn->flags & CF_SHUTR)
+                       return -1;
+               return 0;
+       }
+
+       if (unlikely(chn->buf->p + chn->buf->i > chn->buf->data + chn->buf->size)) {
+               *blk1 = chn->buf->p;
+               *len1 = chn->buf->data + chn->buf->size - chn->buf->p;
+               *blk2 = chn->buf->data;
+               *len2 = chn->buf->i - *len1;
+               return 2;
+       }
+
+       *blk1 = chn->buf->p;
+       *len1 = chn->buf->i;
+       return 1;
+}
+
+/* Gets one text line out of a channel's input buffer from a stream interface.
+ * Return values :
+ *   >0 : number of blocks returned (1 or 2). blk1 is always filled before blk2.
+ *   =0 : not enough data available.
+ *   <0 : no more bytes readable because output is shut.
+ * The '\n' is waited for as long as neither the buffer nor the input are
+ * full. If either of them is full, the string may be returned as is, without
+ * the '\n'. Unused buffers are left in an undefined state.
+ */
+int bi_getline_nc(struct channel *chn,
+                  char **blk1, int *len1,
+                  char **blk2, int *len2)
+{
+       int retcode;
+       int l;
+
+       retcode = bi_getblk_nc(chn, blk1, len1, blk2, len2);
+       if (unlikely(retcode) <= 0)
+               return retcode;
+
+       for (l = 0; l < *len1 && (*blk1)[l] != '\n'; l++);
+       if (l < *len1 && (*blk1)[l] == '\n') {
+               *len1 = l + 1;
+               return 1;
+       }
+
+       if (retcode >= 2) {
+               for (l = 0; l < *len2 && (*blk2)[l] != '\n'; l++);
+               if (l < *len2 && (*blk2)[l] == '\n') {
+                       *len2 = l + 1;
+                       return 2;
+               }
+       }
+
+       if (chn->flags & CF_SHUTW) {
+               /* If we have found no LF and the buffer is shut, then
+                * the resulting string is made of the concatenation of
+                * the pending blocks (1 or 2).
+                */
+               return retcode;
+       }
+
+       /* No LF yet and not shut yet */
+       return 0;
+}
+
 /*
  * Local variables:
  *  c-indent-level: 8