Example #1
0
    def add(self, pkt):
        '''
        Merge the packet into the first chunk it overlaps with. If data was
        added to the end of a chunk, attempts to merge the next chunk (if there
        is one). This way, it is ensured that everything is as fully merged as
        it can be with the current data.

        Args:
        pkt = tcp.Packet
        '''
        if self.finished:
            raise RuntimeError('tried to add packets to a finished tcp.Direction')
        # discard packets with no payload. we don't care about them here
        if pkt.data == '':
            return
        # attempt to merge packet with existing chunks
        merged = False
        for i, chunk in enumerate(self.chunks):
            overlapped, (front, back) = chunk.merge(pkt,
                                             self.create_merge_callback(pkt))
            if overlapped:
                # check if this packet bridged the gap between two chunks
                if back and i < (len(self.chunks)-1):
                    overlapped2, (front2, back2) = chunk.merge(self.chunks[i+1])
                    if overlapped2:
                        # Used to be assert( (not front2) and back2), meaning
                        # the merge was at the back of chunk.  However, that
                        # check seems incorrect if pkt completely
                        # overlaps self.chunks[i+1].  In that case, pkt will
                        # merge into the back of chunk, and chunk will
                        # completely overlap self.chunks[i+1].  In that case, we
                        # have (not front2) and (not back2).
                        assert( (not front2) and (
                            back2 or
                            (seq.lte(pkt.seq_start, self.chunks[i+1].seq_start)
                             and seq.lte(self.chunks[i+1].seq_end, pkt.seq_end))
                            ))
                        if not back2:
                          logging.info('Overlapping chunk(%d-%d) consumed next '
                                       'chunk(%d-%d) in violation of old assert.'
                                       , chunk.seq_start, chunk.seq_end,
                                       self.chunks[i+1].seq_start,
                                       self.chunks[i+1].seq_end)
                        del self.chunks[i+1]
                # if this is the main data chunk, calc final arrival
                if self.seq_start and chunk.seq_start == self.seq_start:
                    if front: # packet was first in stream but just now arriving
                        self.final_arrival_data.insert((self.seq_start, pkt.ts))
                    if back: # usual case
                        self.final_arrival_data.insert((self.final_arrival_pointer, pkt.ts))
                    if not self.final_data_chunk:
                        self.final_data_chunk = chunk
                    self.final_arrival_pointer = self.final_data_chunk.seq_end
                merged = True
                break # skip further chunks
        if not merged:
            # nothing overlapped with the packet
            # we need a new chunk
            self.new_chunk(pkt)
Example #2
0
    def inner_merge(self, newseq, newdata, callback):
        '''
        Internal implementation function for merging, very similar in interface
        to merge_pkt, but concentrates on the nitty-gritty logic of merging, as
        opposed to the high-level logic of merge().

        Args:
        newseq = (seq_begin, seq_end)
        newdata = string, new data
        callback = see new_seq_callback in merge_pkt

        Returns:
        see merge_pkt
        '''
        # setup
        overlapped = False
        added_front_data = False
        added_back_data = False
        # front data?
        if (seq.lt(newseq[0], self.seq_start)
                and seq.lte(self.seq_start, newseq[1])):
            new_data_length = seq.subtract(self.seq_start, newseq[0])
            # slice out new data, stick it on the front
            self.data = newdata[:new_data_length] + self.data
            self.seq_start = newseq[0]
            # notifications
            overlapped = True
            added_front_data = True
            if callback:
                callback(newseq[0])
        # back data?
        if seq.lte(newseq[0], self.seq_end) and seq.lt(self.seq_end,
                                                       newseq[1]):
            new_data_length = seq.subtract(newseq[1], self.seq_end)
            self.data += newdata[-new_data_length:]
            self.seq_end += new_data_length
            # notifications
            overlapped = True
            added_back_data = True
            if callback:
                # the first seq number of new data in the back
                back_seq_start = newseq[1] - new_data_length
                callback(back_seq_start)
        # completely inside?
        if (seq.lte(self.seq_start, newseq[0])
                and seq.lte(newseq[1], self.seq_end)):
            overlapped = True
        # done
        return (overlapped, (added_front_data, added_back_data))
Example #3
0
    def inner_merge(self, newseq, newdata, callback):
        '''
        Internal implementation function for merging, very similar in interface
        to merge_pkt, but concentrates on the nitty-gritty logic of merging, as
        opposed to the high-level logic of merge().

        Args:
        newseq = (seq_begin, seq_end)
        newdata = string, new data
        callback = see new_seq_callback in merge_pkt

        Returns:
        see merge_pkt
        '''
        # setup
        overlapped = False
        added_front_data = False
        added_back_data = False
        # front data?
        if (seq.lt(newseq[0], self.seq_start) and
            seq.lte(self.seq_start, newseq[1])):
            new_data_length = seq.subtract(self.seq_start, newseq[0])
            # slice out new data, stick it on the front
            self.data = newdata[:new_data_length] + self.data
            self.seq_start = newseq[0]
            # notifications
            overlapped = True
            added_front_data = True
            if callback:
                callback(newseq[0])
        # back data?
        if seq.lte(newseq[0], self.seq_end) and seq.lt(self.seq_end, newseq[1]):
            new_data_length = seq.subtract(newseq[1], self.seq_end)
            self.data += newdata[-new_data_length:]
            self.seq_end += new_data_length
            # notifications
            overlapped = True
            added_back_data = True
            if callback:
                # the first seq number of new data in the back
                back_seq_start = newseq[1] - new_data_length
                callback(back_seq_start)
        # completely inside?
        if (seq.lte(self.seq_start, newseq[0]) and
            seq.lte(newseq[1], self.seq_end)):
            overlapped = True
        # done
        return (overlapped, (added_front_data, added_back_data))