fecdec_filter: Detect and ingore duplicate slices.
authorAndre Noll <maan@systemlinux.org>
Sun, 23 May 2010 17:21:02 +0000 (19:21 +0200)
committerAndre Noll <maan@systemlinux.org>
Sun, 23 May 2010 17:21:02 +0000 (19:21 +0200)
This introduces a bit array to keep track of the slices of a FEC group
that have been received so far. This allows to quickly look up whether
the current slice is already present in the FEC group, in which case we
simply ignore it.

This avoids errors of the kind

unregister_task: unregistering fecdec (slot 0) (invalid index vector)

which have been observed with the UDP transport.

The patch also cleans up add_slice() a bit: It replaces the calls to para_malloc()
and memset() by a simple call to para_calloc() and initializes slice_num earlier
so that it can be used throughout the function.

fecdec_filter.c

index 195dbaa..939f7e3 100644 (file)
@@ -61,6 +61,8 @@ struct fecdec_group {
        struct fec_header h;
        /** How many slices received so far. */
        int num_received_slices;
+       /** Bitmap of received slices. */
+       uint8_t received_slices[32];
        /** The size of the \a idx and the \a data arrays below. */
        int num_slices;
        /** Array of indices of the received slices. */
@@ -206,29 +208,40 @@ success:
        return ret;
 }
 
+static bool test_and_set_slice_bit(struct fecdec_group *fg, uint8_t slice_num)
+{
+       uint8_t *p = fg->received_slices + slice_num / 8, old = *p;
+
+       *p |= 1 << (slice_num % 8);
+       return old == *p;
+}
+
 /*
  * returns 1 if slice was added, zero otherwise (because the group was already
- * complete). In any case the number of received slices is being increased by
- * one.
+ * complete or a slice has been received twice).
  */
 static int add_slice(char *buf, struct fecdec_group *fg)
 {
-       int r, slice_num;
+       int r;
+       uint8_t slice_num = fg->h.slice_num;
 
        if (group_complete(fg)) {
                PARA_DEBUG_LOG("group %d complete, ignoring slice %d\n",
-                       fg->h.group_num, fg->h.slice_num);
-               fg->num_received_slices++;
+                       fg->h.group_num, slice_num);
                return 0;
        }
-       slice_num = fg->h.slice_num;
        if (fg->num_slices == 0) {
                fg->num_slices = fg->h.slices_per_group;
                fg->idx = para_malloc(fg->num_slices * sizeof(int));
-               fg->data = para_malloc(fg->num_slices * sizeof(unsigned char *));
-               memset(fg->data, 0, fg->num_slices * sizeof(unsigned char *));
+               fg->data = para_calloc(fg->num_slices * sizeof(unsigned char *));
        }
        r = fg->num_received_slices;
+       /* Check if we already have this slice. */
+       if (test_and_set_slice_bit(fg, slice_num)) {
+               PARA_INFO_LOG("ignoring duplicate slice %d:%d\n", fg->h.group_num,
+                       slice_num);
+               return 0;
+       }
        fg->idx[r] = slice_num;
        fg->data[r] = para_malloc(fg->h.slice_bytes);
        memcpy(fg->data[r], buf, fg->h.slice_bytes);