示例#1
0
 def send_multiple(block_payload, port, is_fin):
     while len(block_payload) > utils.MAX_PACKET_SIZE:
         pckt = Packet(packet_key[0], packet_key[1], True, False,
                       block_payload[:utils.MAX_PACKET_SIZE])
         block_payload = block_payload[utils.MAX_PACKET_SIZE:]
         self.send(pckt, port)
     pckt = Packet(packet_key[0], packet_key[1], True, is_fin,
                   block_payload)
     self.send(pckt, port)
示例#2
0
 def send_multiple(block_payload, port, is_fin):
     packets = []
     for i in range(0, len(block_payload), utils.MAX_PACKET_SIZE):
         pload = block_payload[i:i + utils.MAX_PACKET_SIZE]
         pckt = Packet(packet_key[0], packet_key[1], True, False, pload)
         self.send(pckt, port)
     if is_fin:
         pckt = Packet(packet_key[0], packet_key[1], True, True, '')
         self.send(pckt, port)
 def send_payload_by_splitting(self, payload, source, destination, is_fin):
     packets = []
     while len(payload) > utils.MAX_PACKET_SIZE:
         packets.append(
             Packet(source, destination, True, False,
                    payload[:utils.MAX_PACKET_SIZE]))
         payload = payload[utils.MAX_PACKET_SIZE:]
     packets.append(Packet(source, destination, True, is_fin, payload))
     for pack in packets:
         self.send(pack, self.address_to_port[destination])
示例#4
0
 def packetize_send(self, flow, is_fin, data, port):
     source = flow[0]
     destination = flow[1]
     total_packets = len(data) / utils.MAX_PACKET_SIZE
     for x in range(total_packets):
         packet = data[x * utils.MAX_PACKET_SIZE : (x + 1) * utils.MAX_PACKET_SIZE]
         self.send(Packet(source, destination, True, False, packet), port)
     leftovers = total_packets * utils.MAX_PACKET_SIZE
     last_packet = Packet(source, destination, True, is_fin, data[leftovers:])
     self.send(last_packet, port)
    def send_data_fin(self, data, src, dest):
        while len(data) > utils.MAX_PACKET_SIZE:
            if dest in self.address_to_port:
                self.send(Packet(src, dest, True, False, data[:utils.MAX_PACKET_SIZE]), self.address_to_port[dest])
            else:
                self.send(Packet(src, dest, True, False, data[:utils.MAX_PACKET_SIZE]), self.wan_port)
            data = data[utils.MAX_PACKET_SIZE:]

        if dest in self.address_to_port:
            self.send(Packet(src, dest, True, True, data), self.address_to_port[dest])
        else:
            self.send(Packet(src, dest, True, True, data), self.wan_port)
    def receive(self, packet):
        """ Handles receiving a packet.

        Right now, this function simply forwards packets to clients (if a packet
        is destined to one of the directly connected clients), or otherwise sends
        packets across the WAN. You should change this function to implement the
        functionality described in part 1.  You are welcome to implement private
        helper fuctions that you call here. You should *not* be calling any functions
        or directly accessing any variables in the other middlebox on the other side of
        the WAN; this WAN optimizer should operate based only on its own local state
        and packets that have been received.
        """
        if packet.is_raw_data:
            packet_to_send = packet
            packet_for_later = None
            if (packet.src, packet.dest) not in self.buffers.keys():
                self.buffers[(packet.src, packet.dest)] = {}
                self.buffers[(packet.src, packet.dest)]["packets"] = []
                self.buffers[(packet.src, packet.dest)]["length"] = 0
            if packet.size() + self.buffers[
                (packet.src, packet.dest)]["length"] > WanOptimizer.BLOCK_SIZE:
                diff = WanOptimizer.BLOCK_SIZE - self.buffers[
                    (packet.src, packet.dest)]["length"]
                packet_to_send = Packet(packet.src, packet.dest,
                                        packet.is_raw_data, False,
                                        packet.payload[:diff])
                packet_for_later = Packet(packet.src, packet.dest,
                                          packet.is_raw_data, packet.is_fin,
                                          packet.payload[diff:])
            self.buffers[(packet.src,
                          packet.dest)]['packets'].append(packet_to_send)
            self.buffers[(packet.src, packet.dest)]['length'] += packet.size()
            if packet.is_fin or self.buffers[
                (packet.src,
                 packet.dest)]['length'] >= WanOptimizer.BLOCK_SIZE:
                self.send_block(
                    self.buffers[(packet.src, packet.dest)]["packets"],
                    packet.src, packet.dest, packet.is_fin)
                self.buffers[(packet.src, packet.dest)]['packets'] = []
                self.buffers[(packet.src, packet.dest)]['length'] = 0
                if packet_for_later:
                    self.buffers[(packet.src, packet.dest)]['packets'] = [
                        packet_for_later
                    ]
                    self.buffers[(
                        packet.src,
                        packet.dest)]['length'] = packet_for_later.size()
        else:
            if packet.dest in self.address_to_port:
                if packet.payload in self.hash_to_data.keys():
                    raw_data = self.hash_to_data[packet.payload]
                    self.send_payload_by_splitting(raw_data, packet.src,
                                                   packet.dest, packet.is_fin)
 def packetize_and_send(self, to_send, flow, is_fin, outgoing_port):
     """Packetizes and sends everything in to_send"""
     src, dest = flow[0], flow[1]
     num_full_packets = len(to_send) / utils.MAX_PACKET_SIZE
     for i in range(num_full_packets):
         subset = to_send[i * utils.MAX_PACKET_SIZE:(i + 1) *
                          utils.MAX_PACKET_SIZE]
         new_packet = Packet(src, dest, True, False, subset)
         self.send(new_packet, outgoing_port)
     # leftovers - note will send an empty packet on purpose if nothing left
     subset = to_send[num_full_packets * utils.MAX_PACKET_SIZE:]
     tail_packet = Packet(src, dest, True, is_fin, subset)
     self.send(tail_packet, outgoing_port)
示例#8
0
 def send_block(self, block, src, dest, is_fin=False):
     #DONT FORGET TO COMPUTE THE HASH AND STORE IT
     full_data_string = "".join(block)
     self.hash_to_data[utils.get_hash(full_data_string)] = block
     for i, payload in enumerate(block):
         packet = Packet(src, dest, True, is_fin and i == len(block) - 1,
                         payload)
         if dest in self.address_to_port:
             self.send(packet, self.address_to_port[packet.dest])
         else:
             self.send(packet, self.wan_port)
 def send_remaining_in_buffer(self, flow):
     # Hash and sends whatever is left in the buffer
     curr_buffer = self.flows_to_buffers[flow]
     hashed = utils.get_hash(curr_buffer)
     src, dest = flow[0], flow[1]
     # cache = self.flows_to_caches[flow]
     cache = self.caches
     if hashed in cache:  # send hashed
         hash_packet = Packet(src, dest, False, True,
                              hashed)  # is_fin = True
         self.send(hash_packet, self.wan_port)
     else:  # hash and send raw data
         if (len(curr_buffer) > 0):
             cache[hashed] = curr_buffer
         self.packetize_and_send(curr_buffer, flow, True, self.wan_port)
示例#10
0
    def split_and_send_data(self, packet, data):
        data_len = len(data);

        num_of_full_packets = data_len / utils.MAX_PACKET_SIZE;
        size_of_last_packet = data_len - num_of_full_packets*utils.MAX_PACKET_SIZE;
        for i in range (0, num_of_full_packets):
            start = i*utils.MAX_PACKET_SIZE;
            end = start + utils.MAX_PACKET_SIZE;
            payload = data[start:end];
            curr_packet = Packet(src=packet.src,
                                            dest=packet.dest,
                                            is_raw_data=True,
                                            is_fin=False,
                                            payload=payload);
            self.send_packet(curr_packet);
        last_payload_start = num_of_full_packets*utils.MAX_PACKET_SIZE;
        last_payload_end = last_payload_start + size_of_last_packet;
        last_payload = data[last_payload_start:last_payload_end];
        last_packet = Packet(src=packet.src,
                                            dest=packet.dest,
                                            is_raw_data=True,
                                            is_fin=False,
                                            payload=last_payload);
        self.send_packet(last_packet);
 def flush_buffer_source(self, flow):
     curr_buffer = self.flows_to_buffers[flow]
     hashed = utils.get_hash(curr_buffer)
     cache = self.caches
     # Can assume not handling fin packet
     if (hashed is not None) and (hashed in cache):  # send hashed block
         src, dest = flow
         hash_packet = Packet(src, dest, False, False, hashed)
         self.send(hash_packet, self.wan_port)
     else:  # hash and send data
         cache = self.caches
         curr_buffer = self.flows_to_buffers[flow]
         if hashed is not None:
             cache[hashed] = curr_buffer
         self.packetize_and_send(curr_buffer, flow, False, self.wan_port)
     self.reset_buffer(flow)
示例#12
0
 def send_block(self, list_of_packets, source, destination, is_fin):
     complete_block = ""
     for packet in list_of_packets:
         complete_block += packet.payload
     hashed_data = utils.get_hash(complete_block)
     if hashed_data in self.hash_to_data.keys():
         if packet.dest in self.address_to_port:
             for packet in list_of_packets:
                 self.send(packet, self.address_to_port[packet.dest])
         else:
             hashed_packet = Packet(src=source, dest=destination, is_raw_data=False, is_fin=is_fin,
                                    payload=hashed_data)
             self.send(hashed_packet, self.wan_port)
     else:
         self.hash_to_data[hashed_data] = complete_block
         for packet in list_of_packets:
             self.send_packet(packet)
 def handle_flow_fin_source(self, flow):
     # Hashes and sends whatever is left in the buffer
     # and does flow cleanup
     curr_buffer = self.flows_to_buffers[flow]
     hashed = utils.get_hash(curr_buffer)
     cache = self.caches
     if (hashed is not None) and (hashed in cache):
         src, dest = flow[0], flow[1]
         hash_packet = Packet(src, dest, False, True,
                              hashed)  # is_fin = True
         self.send(hash_packet, self.wan_port)
     else:
         curr_buffer = self.flows_to_buffers[flow]
         if hashed is not None:
             cache[hashed] = curr_buffer
         self.packetize_and_send(curr_buffer, flow, True, self.wan_port)
     self.close_flow(flow)
 def buffer_cache_and_send(self, packet):
     flow = (packet.src, packet.dest)
     curr_buffer = self.flows_to_buffers[flow]
     buffer_size = len(curr_buffer)
     remaining_bytes = self.BLOCK_SIZE - buffer_size
     if packet.size() < remaining_bytes:
         self.flows_to_buffers[flow] = curr_buffer + packet.payload
     else:  # buffer full
         to_hash = curr_buffer + packet.payload[:remaining_bytes]
         hashed = utils.get_hash(to_hash)
         # cache = self.flows_to_caches[flow]
         cache = self.caches
         # All FIN packets sent by send_remaining_in_buffer
         if hashed in cache:  # send hashed block
             hash_packet = Packet(packet.src, packet.dest, False, False,
                                  hashed)
             self.send(hash_packet, self.wan_port)
         else:  # hash and send data
             cache[hashed] = to_hash
             self.packetize_and_send(to_hash, flow, False, self.wan_port)
         self.flows_to_buffers[flow] = packet.payload[remaining_bytes:]
    def receive(self, packet):
        """ Handles receiving a packet.

        Right now, this function simply forwards packets to clients (if a packet
        is destined to one of the directly connected clients), or otherwise sends
        packets across the WAN. You should change this function to implement the
        functionality described in part 2.  You are welcome to implement private
        helper fuctions that you call here. You should *not* be calling any functions
        or directly accessing any variables in the other middlebox on the other side of 
        the WAN; this WAN optimizer should operate based only on its own local state
        and packets that have been received.
        """

        flow = (packet.src, packet.dest)
        if not flow in self.flow_to_buffer:
            self.flow_to_buffer[flow] = ""
        WINDOW_SIZE = 48

        if packet.dest in self.address_to_port:
            # The packet is destined to one of the clients connected to this middlebox;
            # send the packet there.
            if packet.is_raw_data:
                self.send(packet, self.address_to_port[packet.dest])
                self.flow_to_buffer[flow] += packet.payload
                pointer = WINDOW_SIZE
                buffer_size = len(self.flow_to_buffer[flow])
                while pointer <= buffer_size:
                    data_hash = utils.get_hash(
                        self.flow_to_buffer[flow][pointer -
                                                  WINDOW_SIZE:pointer])
                    if (utils.get_last_n_bits(data_hash,
                                              len(self.GLOBAL_MATCH_BITSTRING))
                            == self.GLOBAL_MATCH_BITSTRING):
                        current_buff = self.flow_to_buffer[flow][:pointer]
                        self.cache[utils.get_hash(current_buff)] = current_buff
                        # self.packetize_send(cache[hashed], flow, packet.is_fin, self.address_to_port[packet.dest])
                        self.flow_to_buffer[flow] = self.flow_to_buffer[flow][
                            pointer:]
                        pointer = WINDOW_SIZE
                    else:
                        pointer += 1
            else:
                self.packetize_send(flow, packet.is_fin,
                                    self.cache[packet.payload],
                                    self.address_to_port[packet.dest])

            if packet.is_fin:
                data = utils.get_hash(self.flow_to_buffer[flow])
                if data is not None:
                    current_buff = self.flow_to_buffer[flow]
                    self.cache[data] = current_buff
                del self.flow_to_buffer[flow]

        else:
            # The packet must be destined to a host connected to the other middlebox
            # so send it across the WAN.
            self.flow_to_buffer[flow] += packet.payload
            pointer = WINDOW_SIZE
            buffer_size = len(self.flow_to_buffer[flow])
            while pointer <= buffer_size:
                data_hash = utils.get_hash(
                    self.flow_to_buffer[flow][pointer - WINDOW_SIZE:pointer])
                if (utils.get_last_n_bits(data_hash,
                                          len(self.GLOBAL_MATCH_BITSTRING)) ==
                        self.GLOBAL_MATCH_BITSTRING):
                    block = utils.get_hash(self.flow_to_buffer[flow][:pointer])
                    if block not in self.cache:
                        current_buff = self.flow_to_buffer[flow][:pointer]
                        self.cache[block] = current_buff
                        self.packetize_send(flow, False, current_buff,
                                            self.wan_port)
                    else:
                        src, dest = flow
                        self.send(Packet(src, dest, False, False, block),
                                  self.wan_port)
                    self.flow_to_buffer[flow] = self.flow_to_buffer[flow][
                        pointer:]
                    pointer = WINDOW_SIZE
                else:
                    pointer += 1

            if packet.is_fin:
                flow = (packet.src, packet.dest)
                current_buff = self.flow_to_buffer[flow]
                data_hash = utils.get_hash(current_buff)
                if data_hash not in self.cache:
                    current_buff = self.flow_to_buffer[flow]
                    if data_hash is not None:
                        self.cache[data_hash] = current_buff
                    self.packetize_send(flow, True, current_buff,
                                        self.wan_port)
                else:
                    src, dest = flow[0], flow[1]
                    hash_packet = Packet(src, dest, False, True,
                                         data_hash)  # set is_fin
                    self.send(hash_packet, self.wan_port)
                del self.flow_to_buffer[flow]
示例#16
0
    def receive(self, packet):
        """ Handles receiving a packet.

        Right now, this function simply forwards packets to clients (if a packet
        is destined to one of the directly connected clients), or otherwise sends
        packets across the WAN. You should change this function to implement the
        functionality described in part 1.  You are welcome to implement private
        helper fuctions that you call here. You should *not* be calling any functions
        or directly accessing any variables in the other middlebox on the other side of
        the WAN; this WAN optimizer should operate based only on its own local state
        and packets that have been received.
        """
        if not packet.is_raw_data:
            if packet.dest in self.address_to_port:
                # Can't we assume that we have the hash?
                block = self.hash_to_data[packet.payload]
                packets = []
                while len(block) > utils.MAX_PACKET_SIZE:
                    packets.append(
                        Packet(packet.src, packet.dest, True, False,
                               block[:utils.MAX_PACKET_SIZE]))
                    block = block[utils.MAX_PACKET_SIZE:]
                packets.append(
                    Packet(packet.src, packet.dest, True, packet.is_fin,
                           block))
                for pack in packets:
                    self.send(pack, self.address_to_port[packet.dest])
        else:
            packet_to_send = packet
            packet_for_later = None
            if (packet.src, packet.dest) not in self.buffers.keys():
                self.buffers[(packet.src, packet.dest)] = {}
                self.buffers[(packet.src, packet.dest)]["packets"] = []
                self.buffers[(packet.src, packet.dest)]["length"] = 0

            # Checking if packet needs to be split
            if packet.size() + self.buffers[
                (packet.src, packet.dest)]["length"] > WanOptimizer.BLOCK_SIZE:
                diff = WanOptimizer.BLOCK_SIZE - self.buffers[
                    (packet.src, packet.dest)]["length"]
                # Result should not be True ever
                packet_to_send = Packet(packet.src, packet.dest,
                                        packet.is_raw_data, False,
                                        packet.payload[:diff])
                packet_for_later = Packet(packet.src, packet.dest,
                                          packet.is_raw_data, packet.is_fin,
                                          packet.payload[diff:])

            # Checking if source, destination has been seen before:
            self.buffers[(packet.src,
                          packet.dest)]['packets'].append(packet_to_send)
            self.buffers[(packet.src, packet.dest)]['length'] += packet.size()

            # Checking if we have met block size limit and must therefore send
            if packet.is_fin or self.buffers[
                (packet.src,
                 packet.dest)]['length'] >= WanOptimizer.BLOCK_SIZE:
                packets = self.buffers[(packet.src, packet.dest)]['packets']

                # Create block
                block = ""
                for pack in packets:
                    block += pack.payload

                # If block is in our self.hash_to_data
                if block in self.hash_to_data.values():
                    if packet.dest in self.address_to_port:
                        for pack in packets:
                            self.send(pack, self.address_to_port[pack.dest])
                    else:
                        for hash_key, block_val in self.hash_to_data.iteritems(
                        ):
                            if block == block_val:
                                hash_packet = Packet(packet.src, packet.dest,
                                                     False, packet.is_fin,
                                                     hash_key)
                                break
                        self.send(hash_packet, self.wan_port)

                # If seeing packets for the first time
                else:
                    # Store hash and block to self.hash_to_data
                    self.hash_to_data[utils.get_hash(block)] = block

                    # Send the packets
                    for pack in packets:
                        if packet.dest in self.address_to_port:
                            self.send(pack, self.address_to_port[pack.dest])
                        else:
                            self.send(pack, self.wan_port)

                # Reset after sending out buffer
                self.buffers[(packet.src, packet.dest)]['packets'] = []
                self.buffers[(packet.src, packet.dest)]['length'] = 0
                if packet_for_later:
                    self.buffers[(packet.src, packet.dest)]['packets'] = [
                        packet_for_later
                    ]
                    self.buffers[(
                        packet.src,
                        packet.dest)]['length'] = packet_for_later.size()
示例#17
0
    def receive(self, packet):
        """ Handles receiving a packet.

        Right now, this function simply forwards packets to clients (if a packet
        is destined to one of the directly connected clients), or otherwise sends
        packets across the WAN. You should change this function to implement the
        functionality described in part 1.  You are welcome to implement private
        helper fuctions that you call here. You should *not* be calling any functions
        or directly accessing any variables in the other middlebox on the other side of
        the WAN; this WAN optimizer should operate based only on its own local state
        and packets that have been received.
        """
        if packet.is_raw_data:
            packet_to_send = packet
            packet_for_later = None
            # Check if in the dictionary, if not add it in
            if (packet.src, packet.dest) not in self.buffers.keys():
                self.buffers[(packet.src, packet.dest)] = {}
                self.buffers[(packet.src, packet.dest)]["packets"] = []
                self.buffers[(packet.src, packet.dest)]["length"] = 0
            # First check if you need to split the packet up
            if packet.size() + self.buffers[
                (packet.src, packet.dest)]["length"] > WanOptimizer.BLOCK_SIZE:
                diff = WanOptimizer.BLOCK_SIZE - self.buffers[
                    (packet.src, packet.dest)]["length"]
                packet_to_send = Packet(packet.src, packet.dest,
                                        packet.is_raw_data, False,
                                        packet.payload[:diff])
                packet_for_later = Packet(packet.src, packet.dest,
                                          packet.is_raw_data, packet.is_fin,
                                          packet.payload[diff:])
            # Store the packet into the buffer. Only the first part (if there even was a split) of the packet
            self.buffers[(packet.src,
                          packet.dest)]['packets'].append(packet_to_send)
            self.buffers[(packet.src,
                          packet.dest)]['length'] += packet_to_send.size()
            # Check if you CAN send the packet (either receiving fin or the buffer is full)
            if packet.is_fin or self.buffers[
                (packet.src,
                 packet.dest)]['length'] >= WanOptimizer.BLOCK_SIZE:
                self.send_block(
                    self.buffers[(packet.src, packet.dest)]["packets"],
                    packet.src, packet.dest, packet.is_fin)
                # Check that the second portion of the packet isn't empty
                if packet_for_later is not None:
                    self.buffers[(packet.src, packet.dest)]['packets'] = [
                        packet_for_later
                    ]
                    self.buffers[(
                        packet.src,
                        packet.dest)]['length'] = packet_for_later.size()
                # If it is empty, initialize a new empty one
                else:
                    self.buffers[(packet.src, packet.dest)]['packets'] = []
                    self.buffers[(packet.src, packet.dest)]['length'] = 0
        # If it isn't raw data, just send the data over.
        # If it's going to a CLIENT, send reg data based on HASH
        # If it's going to a WAN, send HASH over.
        # Details in helper method
        else:
            if packet.dest in self.address_to_port:
                if packet.payload in self.hash_to_data.keys():
                    raw_data = self.hash_to_data[packet.payload]
                    self.send_payload_by_splitting(raw_data, packet.src,
                                                   packet.dest, packet.is_fin)
            else:
                if packet.payload in self.hash_to_data.keys():
                    self.send_packet(packet)
    def receive(self, packet):
        """ Handles receiving a packet.

        Right now, this function simply forwards packets to clients (if a packet
        is destined to one of the directly connected clients), or otherwise sends
        packets across the WAN. You should change this function to implement the
        functionality described in part 2.  You are welcome to implement private
        helper fuctions that you call here. You should *not* be calling any functions
        or directly accessing any variables in the other middlebox on the other side of 
        the WAN; this WAN optimizer should operate based only on its own local state
        and packets that have been received.
        """
        #if it's a raw data, always buffer it until it finds delimiter.
        if packet.is_raw_data:
            self.add_to_buffer(packet)
            data = self.collect_from_buffer(packet.src, packet.dest)
            i = 0
            s = 0
            while i + 48 <= len(data):
                lower_13 = utils.get_last_n_bits(utils.get_hash(data[i:i+48]), 13)
                #if it finds delimiter, then send every possible packet that has delimiter
                if lower_13 == self.GLOBAL_MATCH_BITSTRING:
                    self.reset_buffer(packet.src, packet.dest)
                    packet.payload = data[i+48:]
                    self.add_to_buffer(packet)
                    block_string = data[s: i+48]

                    h = utils.get_hash(block_string)
                    if h in self.hash_to_data:
                        self.send_hash(h, packet.src, packet.dest, False)
                    else:
                        self.hash_to_data[h] = block_string
                        while len(block_string) > 0:
                            if packet.dest in self.address_to_port:
                                self.send(Packet(packet.src, packet.dest, True, False, block_string[:utils.MAX_PACKET_SIZE]), self.address_to_port[packet.dest])
                            else:
                                self.send(Packet(packet.src, packet.dest, True, False, block_string[:utils.MAX_PACKET_SIZE]), self.wan_port)
                            block_string = block_string[utils.MAX_PACKET_SIZE:]
                    s = i + 48
                i += 1

            #fin packet, dump it all
            if packet.is_fin:
                data = self.collect_from_buffer(packet.src, packet.dest)
                self.reset_buffer(packet.src, packet.dest)

                h = utils.get_hash(data)
                if h in self.hash_to_data:
                    self.send_hash(h, packet.src, packet.dest, True)
                else:
                    self.hash_to_data[h] = data
                    self.send_data_fin(data, packet.src, packet.dest)
                
        else:
            # case where you receive a hash from the WAN
            # look up the raw data and forward it to the correct address on your LAN
            raw_data = self.hash_to_data[packet.payload]
            while len(raw_data) > utils.MAX_PACKET_SIZE:
                self.send(Packet(packet.src, packet.dest, True, False, raw_data[:utils.MAX_PACKET_SIZE]), self.address_to_port[packet.dest])
                raw_data = raw_data[utils.MAX_PACKET_SIZE:]
            self.send(Packet(packet.src, packet.dest, True, packet.is_fin, raw_data), self.address_to_port[packet.dest])
示例#19
0
    def receive(self, packet):
        """ Handles receiving a packet.

        Right now, this function simply forwards packets to clients (if a packet
        is destined to one of the directly connected clients), or otherwise sends
        packets across the WAN. You should change this function to implement the
        functionality described in part 1.  You are welcome to implement private
        helper fuctions that you call here. You should *not* be calling any functions
        or directly accessing any variables in the other middlebox on the other side of 
        the WAN; this WAN optimizer should operate based only on its own local state
        and packets that have been received.
        """
        flow = (packet.src, packet.dest)
        if not flow in self.flow_to_buffer:
            self.flow_to_buffer[flow] = ""
        current_buff = self.flow_to_buffer[flow]

        if packet.dest in self.address_to_port:
            # The packet is destined to one of the clients connected to this middlebox, send the packet there.
            if packet.is_raw_data:
                self.send(packet, self.address_to_port[packet.dest])
                empty_space = self.BLOCK_SIZE - len(current_buff)
                if packet.size() < empty_space:
                    self.flow_to_buffer[flow] = current_buff + packet.payload
                else:
                    hash_data = utils.get_hash(current_buff + packet.payload[:empty_space])
                    self.cache[hash_data] = current_buff + packet.payload[:empty_space]
                    self.flow_to_buffer[flow] = packet.payload[empty_space:]    
            # packet already in cache
            else:
                data = self.cache[packet.payload]
                self.packetize_send(flow, packet.is_fin, data, self.address_to_port[packet.dest])

            if packet.is_fin:
                current_buff = self.flow_to_buffer[flow]
                if (len(current_buff) > 0):
                    hash_data = utils.get_hash(current_buff)
                    self.cache[hash_data] = current_buff
                del self.flow_to_buffer[flow]
        #send it across the WAN        
        else: 
            empty_space = self.BLOCK_SIZE - len(current_buff)
            if packet.size() < empty_space:
                self.flow_to_buffer[flow] = current_buff + packet.payload
            else: # buffer is full, send data
                hash_data = utils.get_hash(current_buff + packet.payload[:empty_space])
                if hash_data not in self.cache:
                    self.cache[hash_data] = current_buff + packet.payload[:empty_space]
                    self.packetize_send(flow, False, current_buff + packet.payload[:empty_space], self.wan_port)
                else:
                    self.send(Packet(packet.src, packet.dest, False, False, hash_data), self.wan_port)
                # update buffer
                self.flow_to_buffer[flow] = packet.payload[empty_space:]

            if packet.is_fin:
                source = flow[0]
                destination = flow[1]
                current_buff = self.flow_to_buffer[flow]
                data_hash = utils.get_hash(current_buff)
                if data_hash not in self.cache:
                    if (len(current_buff) > 0):
                        self.cache[data_hash] = current_buff
                    self.packetize_send(flow, True, current_buff, self.wan_port)
                else:
                    hash_packet = Packet(source, destination, False, True, data_hash) #  set is_fin flag
                    self.send(hash_packet, self.wan_port)
                # delete the flow
                del self.flow_to_buffer[flow]
示例#20
0
    def receive(self, packet):
        """ Handles receiving a packet.

        Right now, this function simply forwards packets to clients (if a packet
        is destined to one of the directly connected clients), or otherwise sends
        packets across the WAN. You should change this function to implement the
        functionality described in part 1.  You are welcome to implement private
        helper fuctions that you call here. You should *not* be calling any functions
        or directly accessing any variables in the other middlebox on the other side of 
        the WAN; this WAN optimizer should operate based only on its own local state
        and packets that have been received.
        """
        #always buffer raw data until ready to send (full buffer or FIN packet)
        #this raw data could be from someone on your LAN or from the WAN, either way
        #you buffer and forward to the right address when the buffer is filled
        #or the packet is a FIN packet
        if packet.is_raw_data:
            current_buffer_size = self.buffer_size(
                self.get_buffer(packet.src, packet.dest))
            if current_buffer_size + packet.size() < self.BLOCK_SIZE:
                self.add_to_buffer(packet)
                #fin packet, dump it all
                if packet.is_fin:
                    to_send = self.collect_from_buffer(packet.src, packet.dest)
                    self.reset_buffer(packet.src, packet.dest)
                    full_data_string = "".join(to_send)
                    h = utils.get_hash(full_data_string)
                    if h in self.hash_to_data:
                        self.send_hash(h, packet.src, packet.dest, True)
                    else:
                        self.hash_to_data[h] = to_send
                        self.send_block(to_send, packet.src, packet.dest, True)
            else:
                # buffer full, time to send
                to_send = self.collect_from_buffer(packet.src, packet.dest)
                #split up this packet's payload: the first few bytes become
                #added to this block, the rest get stuffed in later
                boundary = self.BLOCK_SIZE - current_buffer_size
                high_half = packet.payload[0:boundary]
                low_half = packet.payload[boundary:]
                to_send.append(high_half)
                self.reset_buffer(packet.src, packet.dest)

                #Send the first block
                full_data_string = "".join(to_send)
                h = utils.get_hash(full_data_string)
                if h in self.hash_to_data:
                    self.send_hash(h, packet.src, packet.dest)
                else:
                    self.hash_to_data[h] = to_send
                    self.send_block(to_send, packet.src, packet.dest)

                #buffer the rest of the packet, else hash/send it as a second block if FIN
                if not packet.is_fin:
                    self.add_to_buffer(
                        Packet(packet.src, packet.dest, True, False, low_half))
                else:
                    h2 = utils.get_hash(low_half)
                    if h2 in self.hash_to_data:
                        self.send_hash(h2, packet.src, packet.dest, True)
                    else:
                        self.send_block([low_half], packet.src, packet.dest,
                                        True)

        else:
            # case where you receive a hash from the WAN
            # look up the raw data and forward it to the correct address on your LAN
            if packet.payload not in self.hash_to_data:
                print("REEEEE THIS SHOULDN'T HAPPEN!" + str(packet))
            raw_data = self.hash_to_data[packet.payload]
            self.send_block(raw_data, packet.src, packet.dest, packet.is_fin)
示例#21
0
 def send_hash(self, data_hash, src, dest, is_fin=False):
     packet = Packet(src, dest, False, is_fin, data_hash)
     if dest in self.address_to_port:
         self.send(packet, self.address_to_port[packet.dest])
     else:
         self.send(packet, self.wan_port)
示例#22
0
    def receive(self, packet):
        """ Handles receiving a packet.

        Right now, this function simply forwards packets to clients (if a packet
        is destined to one of the directly connected clients), or otherwise sends
        packets across the WAN. You should change this function to implement the
        functionality described in part 2.  You are welcome to implement private
        helper fuctions that you call here. You should *not* be calling any functions
        or directly accessing any variables in the other middlebox on the other side of 
        the WAN; this WAN optimizer should operate based only on its own local state
        and packets that have been received.
        """
        src, dest = packet.src, packet.dest;

        # Check if in the dictionary, if not add it in
        if (packet.src, packet.dest) not in self.buffers.keys():
            self.buffers[(packet.src, packet.dest)] = {};
            self.buffers[(packet.src, packet.dest)]["unhashed_data"] = "";
            self.buffers[(packet.src, packet.dest)]["end"] = 48;

        if packet.is_raw_data:
                # print str(self) + str(len(packet.payload))
                # Grab data from buffers{}, will write data back in at the end to reduce overhead from while loops
                unhashed_data = self.buffers[(src, dest)]["unhashed_data"] + packet.payload;
                end = self.buffers[(src, dest)]["end"];
                break_loop = False;

                # First while loop loops through all of unhashed_data
                while (break_loop == False):
                    block = unhashed_data[:end];
                    block_hash = utils.get_hash(block);
                    window_hash = utils.get_hash(block[end-48:end])
                    block_key = utils.get_last_n_bits(window_hash, 13);
                    entered_inner_loop = False;

                    # Second while loop finds the first block that ends with the delimiter
                    while (block_key != WanOptimizer.GLOBAL_MATCH_BITSTRING and end <= len(unhashed_data)):
                        entered_inner_loop = True;
                        block = unhashed_data[:end];
                        block_hash = utils.get_hash(block);
                        window_hash = utils.get_hash(block[end-48:end])
                        block_key = utils.get_last_n_bits(window_hash, 13);
                        end = end + 1;

                    if entered_inner_loop:
                        end = end - 1;  # Need to subtract by 1 because we will skip one character
                                        # when making consecutive blocks because of end = end + 1.

                    # If we didn't find a valid block, leave the loop
                    if block_key != WanOptimizer.GLOBAL_MATCH_BITSTRING:
                        break_loop = True;
                        break;

                    # If we've already hashed this block, then send out the hash
                    # Else we hash it and then send out the whole block
                    if block_hash in self.hash_to_data:
                        hash_packet = Packet(src=packet.src,
                                                    dest=packet.dest,
                                                    is_raw_data=False,
                                                    is_fin=False,
                                                    payload=block_hash);
                        self.send_packet(hash_packet);
                    else:
                        self.hash_to_data[block_hash] = block;
                        self.split_and_send_data(packet, block);

                    unhashed_data = unhashed_data[end:]; # next window starts at the end of the previous
                    end = 48;

                # Where we send fin packet
                if packet.is_fin:
                    # Hash and send whatever data is left in buffer
                    if unhashed_data:
                        hashcode = utils.get_hash(unhashed_data)
                        if hashcode in self.hash_to_data.keys():
                            hash_packet = Packet(src=packet.src,
                                                    dest=packet.dest,
                                                    is_raw_data=False,
                                                    is_fin=False,
                                                    payload=hashcode);
                            self.send_packet(hash_packet);
                        else:
                            self.split_and_send_data(packet, unhashed_data);
                            self.hash_to_data[utils.get_hash(unhashed_data)] = unhashed_data;

                    # Send empty fin packet
                    packet.is_fin = True;
                    packet.is_raw_data = True;
                    packet.payload = ""
                    self.send_packet(packet);
                    unhashed_data = "";
                    end = 48;
                
                self.buffers[(src, dest)]["unhashed_data"] = unhashed_data;
                self.buffers[(src, dest)]["end"] = end;

        else:
            if packet.payload in self.hash_to_data.keys():
                prev_payload = packet.payload;

                unhashed_data = self.buffers[(src, dest)]["unhashed_data"];
                # If there is unhashed data, hash it and send it out
                if unhashed_data:
                    hashcode = utils.get_hash(unhashed_data)
                    if hashcode in self.hash_to_data.keys():
                        hash_packet = Packet(src=packet.src,
                                                dest=packet.dest,
                                                is_raw_data=False,
                                                is_fin=False,
                                                payload=hashcode);
                        self.send_packet(hash_packet)
                    else:
                        self.hash_to_data[utils.get_hash(unhashed_data)] = unhashed_data;
                        self.split_and_send_data(packet, unhashed_data);

                    self.buffers[(src, dest)]["unhashed_data"] = "";
                    self.buffers[(src, dest)]["end"] = 48;

                if packet.dest in self.address_to_port:
                    raw_data = self.hash_to_data[prev_payload]
                    self.split_and_send_data(packet, raw_data)
                    if packet.is_fin:
                        packet.payload = "";
                        packet.is_raw_data = True;
                        self.send_packet(packet);
                else:
                   self.send_packet(packet)
示例#23
0
 def send_with_hash(hasch, is_fin):
     #send hash packet
     is_raw_data = False
     hash_packet = Packet(packet_key[0], packet_key[1], is_raw_data,
                          is_fin, hasch)
     self.send(hash_packet, self.wan_port)