]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ncbuf: define various insertion modes
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 9 May 2022 09:59:15 +0000 (11:59 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 12 May 2022 16:27:05 +0000 (18:27 +0200)
Define three different ways to proceed insertion. This configures how
overlapping data is treated.
- NCB_ADD_PRESERVE : in this mode, old data are kept during insertion.
- NCB_ADD_OVERWRT : new data will overwrite old ones.
- NCB_ADD_COMPARE : this mode adds a new test in check stage. The
  overlapping old and new data must be identical or else the insertion
  is not conducted. An error NCB_RET_DATA_REJ is used in this case.

The mode is specified with a new argument to ncb_add() function.

include/haproxy/ncbuf-t.h
include/haproxy/ncbuf.h
src/ncbuf.c

index 05bebe6f04579b15d10507c75f08c960ad925470..fdeb58babeda4e0f283d71ac01b024fffe7481d7 100644 (file)
@@ -91,6 +91,14 @@ enum ncb_ret {
        NCB_RET_OK = 0,   /* no error */
 
        NCB_RET_GAP_SIZE, /* operation would create a too small gap */
+       NCB_RET_DATA_REJ, /* operation would overwrite data with different one */
+};
+
+/* Define how insert is conducted in regards with already stored data. */
+enum ncb_add_mode {
+       NCB_ADD_PRESERVE, /* keep the already stored data and only insert in gaps */
+       NCB_ADD_OVERWRT,  /* overwrite old data with new ones */
+       NCB_ADD_COMPARE,  /* compare before insert : if new data are different do not proceed */
 };
 
 #endif /* _HAPROXY_NCBUF_T_H */
index c935c1eb605b85110ee2d3e858dc2a95d82cbe2b..a13dd508de767da36e538c2c80185847fb979834 100644 (file)
@@ -19,6 +19,6 @@ int ncb_is_full(const struct ncbuf *buf);
 ncb_sz_t ncb_data(const struct ncbuf *buf, ncb_sz_t offset);
 
 enum ncb_ret ncb_add(struct ncbuf *buf, ncb_sz_t off,
-                     const char *data, ncb_sz_t len);
+                     const char *data, ncb_sz_t len, enum ncb_add_mode mode);
 
 #endif /* _HAPROXY_NCBUF_H */
index 59224075570eeaeb12773ed294280466e752fdf0..db0864984c4103e97ce4180f066e35960688bbb0 100644 (file)
@@ -207,13 +207,16 @@ static ncb_sz_t ncb_blk_off(const struct ncb_blk blk, ncb_sz_t off)
 
 /* Simulate insertion in <buf> of <data> of length <len> at offset <off>. This
  * ensures that minimal block size are respected for newly formed gaps. <blk>
- * must be the block where the insert operation begins.
+ * must be the block where the insert operation begins. If <mode> is
+ * NCB_ADD_COMPARE, old and new overlapped data are compared to validate the
+ * insertion.
  *
  * Returns NCB_RET_OK if insertion can proceed.
  */
 static enum ncb_ret ncb_check_insert(const struct ncbuf *buf,
                                      struct ncb_blk blk, ncb_sz_t off,
-                                     const char *data, ncb_sz_t len)
+                                     const char *data, ncb_sz_t len,
+                                     enum ncb_add_mode mode)
 {
        ncb_sz_t off_blk = ncb_blk_off(blk, off);
        ncb_sz_t to_copy;
@@ -239,6 +242,24 @@ static enum ncb_ret ncb_check_insert(const struct ncbuf *buf,
                        if (gap_sz < NCB_GAP_MIN_SZ && !ncb_blk_is_last(buf, blk))
                                return NCB_RET_GAP_SIZE;
                }
+               else if (!(blk.flag & NCB_BK_F_GAP) && mode == NCB_ADD_COMPARE) {
+                       /* Compare memory of data block in NCB_ADD_COMPARE mode. */
+                       const ncb_sz_t off_blk = ncb_blk_off(blk, off);
+                       char *st = ncb_peek(buf, off);
+
+                       to_copy = MIN(left, blk.sz - off_blk);
+                       if (st + to_copy > ncb_wrap(buf)) {
+                               const ncb_sz_t sz1 = ncb_wrap(buf) - st;
+                               if (memcmp(st, data, sz1))
+                                       return NCB_RET_DATA_REJ;
+                               if (memcmp(ncb_orig(buf), data + sz1, to_copy - sz1))
+                                       return NCB_RET_DATA_REJ;
+                       }
+                       else {
+                               if (memcmp(st, data, to_copy))
+                                       return NCB_RET_DATA_REJ;
+                       }
+               }
 
                left -= to_copy;
                data += to_copy;
@@ -252,13 +273,15 @@ static enum ncb_ret ncb_check_insert(const struct ncbuf *buf,
 
 /* Fill new <data> of length <len> inside an already existing data <blk> at
  * offset <off>. Offset is relative to <blk> so it cannot be greater than the
- * block size.
+ * block size. <mode> specifies if old data are preserved or overwritten.
  */
 static ncb_sz_t ncb_fill_data_blk(const struct ncbuf *buf,
                                   struct ncb_blk blk, ncb_sz_t off,
-                                  const char *data, ncb_sz_t len)
+                                  const char *data, ncb_sz_t len,
+                                  enum ncb_add_mode mode)
 {
        const ncb_sz_t to_copy = MIN(len, blk.sz - off);
+       char *ptr = NULL;
 
        BUG_ON_HOT(off > blk.sz);
        /* This can happens due to previous ncb_blk_find() usage. In this
@@ -267,6 +290,19 @@ static ncb_sz_t ncb_fill_data_blk(const struct ncbuf *buf,
        if (off == blk.sz)
                return 0;
 
+       if (mode == NCB_ADD_OVERWRT) {
+               ptr = ncb_peek(buf, blk.off + off);
+
+               if (ptr + to_copy >= ncb_wrap(buf)) {
+                       const ncb_sz_t sz1 = ncb_wrap(buf) - ptr;
+                       memcpy(ptr, data, sz1);
+                       memcpy(ncb_orig(buf), data + sz1, to_copy - sz1);
+               }
+               else {
+                       memcpy(ptr, data, to_copy);
+               }
+       }
+
        return to_copy;
 }
 
@@ -438,9 +474,11 @@ ncb_sz_t ncb_data(const struct ncbuf *buf, ncb_sz_t off)
  *
  * Returns NCB_RET_OK on success. On error the following codes are returned :
  * - NCB_RET_GAP_SIZE : cannot add data because the gap formed is too small
+ * - NCB_RET_DATA_REJ : old data would be overwritten by different ones in
+ *                      NCB_ADD_COMPARE mode.
  */
 enum ncb_ret ncb_add(struct ncbuf *buf, ncb_sz_t off,
-                     const char *data, ncb_sz_t len)
+                     const char *data, ncb_sz_t len, enum ncb_add_mode mode)
 {
        struct ncb_blk blk;
        ncb_sz_t left = len;
@@ -456,7 +494,7 @@ enum ncb_ret ncb_add(struct ncbuf *buf, ncb_sz_t off,
        blk = ncb_blk_find(buf, off);
 
        /* Check if insertion is possible. */
-       ret = ncb_check_insert(buf, blk, off, data, len);
+       ret = ncb_check_insert(buf, blk, off, data, len, mode);
        if (ret != NCB_RET_OK)
                return ret;
 
@@ -503,7 +541,7 @@ enum ncb_ret ncb_add(struct ncbuf *buf, ncb_sz_t off,
                        }
                }
                else {
-                       done = ncb_fill_data_blk(buf, blk, off_blk, data, left);
+                       done = ncb_fill_data_blk(buf, blk, off_blk, data, left, mode);
                }
 
                BUG_ON_HOT(done > blk.sz || done > left);