Esempio n. 1
0
    def send_packets(self, trace_connection, trace, sent_packets):

        self.logger.debug('send trace thread started')

        _, trace_packets = trace

        index = -1
        prev_packet_time = None
        for packet in trace_packets:

            index += 1

            packet_delta = 0
            if prev_packet_time != None:
                packet_delta = packet['timestamp'] - prev_packet_time
            prev_packet_time = packet['timestamp']

            if packet_delta > 0:
                MUtils.busywait_sleep(packet_delta)

            seq = RTPHeader.get_sequence_number(packet['payload'])
            if seq == None:
                self.logger.error('BUG: packet to be sent does not have an RTP header!')
                continue
            sent_packets[seq] = index, time.time(), packet['payload']

            trace_connection.sendall(packet['payload'])
            #self.logger.debug('packet sent size=%s' % len(packet['payload'])) 

        trace_connection.sendall(RTPTraceSender.end_message)

        self.logger.debug('sender thread has finished')
Esempio n. 2
0
    def send_packets(self, trace_connection, trace, sent_packets):

        self.logger.debug('send trace thread started')

        _, trace_packets = trace

        seq = -1
        prev_packet_time = None
        for packet in trace_packets:

            seq += 1

            packet_delta = 0
            if prev_packet_time != None:
                packet_delta = packet['timestamp'] - prev_packet_time
            prev_packet_time = packet['timestamp']

            if packet_delta > 0:
                MUtils.busywait_sleep(packet_delta)

            timestamp = time.time()
            payload = PacketFooter.write(packet['payload'], seq,
                                         int(timestamp * 1000))
            sent_packets[seq] = seq, timestamp, payload

            trace_connection.sendall(payload)
            #self.logger.debug('packet sent size=%s' % len(packet['payload']))

        trace_connection.sendall(RandomTraceSender.end_message)

        self.logger.debug('sender thread has finished')
Esempio n. 3
0
    def send_packets(self, trace_connection, trace, sent_packets):

        self.logger.debug('send trace thread started')

        _, trace_packets = trace

        index = -1
        prev_packet_time = None
        for packet in trace_packets:

            index += 1

            packet_delta = 0
            if prev_packet_time != None:
                packet_delta = packet['timestamp'] - prev_packet_time
            prev_packet_time = packet['timestamp']

            if packet_delta > 0:
                MUtils.busywait_sleep(packet_delta)

            seq = RTPHeader.get_sequence_number(packet['payload'])
            if seq == None:
                self.logger.error(
                    'BUG: packet to be sent does not have an RTP header!')
                continue
            sent_packets[seq] = index, time.time(), packet['payload']

            trace_connection.sendall(packet['payload'])
            #self.logger.debug('packet sent size=%s' % len(packet['payload']))

        trace_connection.sendall(RTPTraceSender.end_message)

        self.logger.debug('sender thread has finished')
Esempio n. 4
0
 def read_client_info(self):
     client_info = MUtils.read_json(self.fd)
     if 'device_info' not in client_info or\
        'phone_status' not in client_info or\
        'network_status' not in client_info:
         raise ValueError('failed to read client info: incomplete client info received')
     if 'unique_id' not in client_info['device_info']:
         raise ValueError('failed to read client info: client id not found')
     return client_info
Esempio n. 5
0
 def read_client_info(self):
     client_info = MUtils.read_json(self.fd)
     if 'device_info' not in client_info or\
        'phone_status' not in client_info or\
        'network_status' not in client_info:
         raise ValueError(
             'failed to read client info: incomplete client info received')
     if 'unique_id' not in client_info['device_info']:
         raise ValueError('failed to read client info: client id not found')
     return client_info
Esempio n. 6
0
    def run(self):

        timestamp = time.time()
        trace_filepath = os.path.join(self.output_dir, '%s.trace' % int(timestamp))
        pcap_filepath = os.path.join(self.output_dir, '%s.pcap' % int(timestamp))

        try:
            trace_name = self.control_connection_fd.readline()
            trace_id = self.control_connection_fd.readline()
            if not (trace_name and trace_id):
                raise socket.error('connection closed by remote host')
            trace_id = int(trace_id)
            trace_name = trace_name.strip()
            trace = self.load_trace(trace_name, trace_id)
            self.logger.info('trace name=%s trace id=%s pcap=%s' %
                             (trace_name, trace_id, pcap_filepath))
        except (ValueError, IOError, socket.error, socket.timeout) as e:
            self.logger.error('trace setup failed (%s)' % e)
            raise

        trace_connection = None
        try:
            self.logger.info('opening trace connection')
            trace_connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            trace_connection.bind((self.listen_IP, 0)) # use a random port
            listen_address = trace_connection.getsockname()

            # Create the tcpdump object first and sleep one second,
            # so we can sure all the packets get sniffed
            self.logger.info('opening capture file %s' % pcap_filepath)
            tcpdump = NetUtils.Tcpdump(Config.CAPTURE_INTERFACE, self.client_IP,
                                       listen_address[1], pcap_filepath)
            tcpdump.make_thread().start()
            time.sleep(1)

            # Tell the client what port should be used for the measurement
            self.control_connection_fd.write(str(listen_address[0]) + '\n')
            self.control_connection_fd.write(str(listen_address[1]) + '\n')
            self.control_connection_fd.flush()

            # Receive a first packet to punch the client-side NAT and set
            # the trace destination according to the packet's source address
            client_side_address = self.receive_punch_packet(trace_connection)
            trace_connection.connect(client_side_address)

            # Start one thread that receives the replies 
            replies = []
            receiver = threading.Thread(target = self.recv_replies,
                                        args = (trace_connection, replies))
            receiver.start()

            # Start another thread that sends the trace packets
            sent_packets = {}
            sender = threading.Thread(target = self.send_packets,
                                      args = (trace_connection, trace, sent_packets))
            sender.start()

            # Wait for the threads to complete and close the connection
            receiver.join()
            sender.join()
            self.logger.info('closing trace connection')
            trace_connection.close()
            tcpdump.kill()

            self.logger.debug('saving server side measurement info')
            server_side_info = {}
            server_side_info['trace_rtts'] = self.get_trace_RTTs(replies, sent_packets)
            server_side_info['sent_timestamps'] = self.get_sent_timestamps(sent_packets)

            self.logger.info('reading measurement info from client')
            client_side_info = MUtils.read_compressed_json(self.control_connection_fd)
            try:
                if len(client_side_info['recv_timestamps']) != len(client_side_info['recv_seq']):
                    raise ValueError('len(recv_timestamps) != len(recv_seq)')
            except (KeyError, ValueError) as e:
                self.logger.error('BUG client side info is not valid (%s)' % e)
                raise ValueError('invalid client side info')

            # Use the data sent from the client to reconstruct the trace it received
            recv_packets = self.rebuild_received_trace_packets(client_side_info, sent_packets)

            self.logger.info('sending trace statistics')
            trace_statistics = self.compute_trace_statistics(sent_packets,
                                                             client_side_info['recv_seq'],
                                                             recv_packets)
            MUtils.send_json(self.control_connection_fd, trace_statistics)

            result = {}
            result['timestamp'] = timestamp 
            result['trace_id'] = trace_id
            result['client_side_info'] = client_side_info
            result['server_side_info'] = server_side_info
            result['statistics'] = trace_statistics
            result['server_address'] = {'IP': listen_address[0],
                                        'port': listen_address[1]}
            result['client_address'] = {'IP': client_side_address[0],
                                        'port': client_side_address[1]}
            result['trace_filename'] = os.path.basename(trace_filepath)
            result['pcap_filename'] = os.path.basename(pcap_filepath)

            # Save the resulting trace
            self.save_sent_trace(recv_packets, result, trace_filepath)

            return result
        except (ValueError, socket.error, socket.timeout, zlib.error) as e:
            self.logger.error('read trace failed (%s)' % e)
            raise
        finally:
            # To be sure that the trace connection
            # gets closed even in case of errors
            if trace_connection: trace_connection.close()
Esempio n. 7
0
    def run(self):

        timestamp = time.time()
        trace_filepath = os.path.join(self.output_dir,
                                      '%s.trace' % int(timestamp))
        pcap_filepath = os.path.join(self.output_dir,
                                     '%s.pcap' % int(timestamp))

        try:
            trace_name = self.control_connection_fd.readline()
            trace_id = self.control_connection_fd.readline()
            if not (trace_name and trace_id):
                raise socket.error('connection closed by remote host')
            trace_id = int(trace_id)
            trace_name = trace_name.strip()
            trace = self.load_trace(trace_name, trace_id)
            self.logger.info('trace name=%s trace id=%s pcap=%s' %
                             (trace_name, trace_id, pcap_filepath))
        except (ValueError, IOError, socket.error, socket.timeout) as e:
            self.logger.error('trace setup failed (%s)' % e)
            raise

        trace_connection = None
        try:
            self.logger.info('opening trace connection')
            trace_connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            trace_connection.bind((self.listen_IP, 0))  # use a random port
            listen_address = trace_connection.getsockname()

            # Create the tcpdump object first and sleep one second,
            # so we can sure all the packets get sniffed
            self.logger.info('opening capture file %s' % pcap_filepath)
            tcpdump = NetUtils.Tcpdump(Config.CAPTURE_INTERFACE,
                                       self.client_IP, listen_address[1],
                                       pcap_filepath)
            tcpdump.make_thread().start()
            time.sleep(1)

            # Tell the client what port should be used for the measurement
            self.control_connection_fd.write(str(listen_address[0]) + '\n')
            self.control_connection_fd.write(str(listen_address[1]) + '\n')
            self.control_connection_fd.flush()

            # Receive a first packet to punch the client-side NAT and set
            # the trace destination according to the packet's source address
            client_side_address = self.receive_punch_packet(trace_connection)
            trace_connection.connect(client_side_address)

            # Start one thread that receives the replies
            replies = []
            receiver = threading.Thread(target=self.recv_replies,
                                        args=(trace_connection, replies))
            receiver.start()

            # Start another thread that sends the trace packets
            sent_packets = {}
            sender = threading.Thread(target=self.send_packets,
                                      args=(trace_connection, trace,
                                            sent_packets))
            sender.start()

            # Wait for the threads to complete and close the connection
            receiver.join()
            sender.join()
            self.logger.info('closing trace connection')
            trace_connection.close()
            tcpdump.kill()

            self.logger.debug('saving server side measurement info')
            server_side_info = {}
            server_side_info['trace_rtts'] = self.get_trace_RTTs(
                replies, sent_packets)
            server_side_info['sent_timestamps'] = self.get_sent_timestamps(
                sent_packets)

            self.logger.info('reading measurement info from client')
            client_side_info = MUtils.read_compressed_json(
                self.control_connection_fd)
            try:
                if len(client_side_info['recv_timestamps']) != len(
                        client_side_info['recv_seq']):
                    raise ValueError('len(recv_timestamps) != len(recv_seq)')
            except (KeyError, ValueError) as e:
                self.logger.error('BUG client side info is not valid (%s)' % e)
                raise ValueError('invalid client side info')

            # Use the data sent from the client to reconstruct the trace it received
            recv_packets = self.rebuild_received_trace_packets(
                client_side_info, sent_packets)

            self.logger.info('sending trace statistics')
            trace_statistics = self.compute_trace_statistics(
                sent_packets, client_side_info['recv_seq'], recv_packets)
            MUtils.send_json(self.control_connection_fd, trace_statistics)

            result = {}
            result['timestamp'] = timestamp
            result['trace_id'] = trace_id
            result['client_side_info'] = client_side_info
            result['server_side_info'] = server_side_info
            result['statistics'] = trace_statistics
            result['server_address'] = {
                'IP': listen_address[0],
                'port': listen_address[1]
            }
            result['client_address'] = {
                'IP': client_side_address[0],
                'port': client_side_address[1]
            }
            result['trace_filename'] = os.path.basename(trace_filepath)
            result['pcap_filename'] = os.path.basename(pcap_filepath)

            # Save the resulting trace
            self.save_sent_trace(recv_packets, result, trace_filepath)

            return result
        except (ValueError, socket.error, socket.timeout, zlib.error) as e:
            self.logger.error('read trace failed (%s)' % e)
            raise
        finally:
            # To be sure that the trace connection
            # gets closed even in case of errors
            if trace_connection: trace_connection.close()
Esempio n. 8
0
    def run(self):

        timestamp = time.time()
        trace_filepath = os.path.join(self.output_dir, '%s.trace' % int(timestamp))
        pcap_filepath = os.path.join(self.output_dir, '%s.pcap' % int(timestamp))

        try:
            trace_id = self.control_connection_fd.readline()
            trace_size = self.control_connection_fd.readline()
            if not (trace_id and trace_size):
                raise socket.error('connection closed by remote host')
            trace_id = int(trace_id)
            trace_size = int(trace_size)
            self.logger.info('trace id=%s size=%s file=%s pcap=%s' %
                             (trace_id, trace_size, trace_filepath, pcap_filepath))
        except (ValueError, socket.error, socket.timeout) as e:
            self.logger.error('trace setup failed (%s)' % e)
            raise

        trace_connection = None
        try:
            self.logger.info('opening trace connection')
            trace_connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            trace_connection.bind((self.listen_IP, 0)) # use a random port
            listen_address = trace_connection.getsockname()

            # Create the tcpdump object first and sleep one second,
            # so we can sure all the packets get sniffed
            self.logger.info('opening capture file %s' % pcap_filepath)
            tcpdump = NetUtils.Tcpdump(Config.CAPTURE_INTERFACE, self.client_IP,
                                       listen_address[1], pcap_filepath)
            tcpdump.make_thread().start()
            time.sleep(1)

            self.control_connection_fd.write(str(listen_address[0]) + '\n')
            self.control_connection_fd.write(str(listen_address[1]) + '\n')
            self.control_connection_fd.flush()

            # Receive the trace packets
            client_port, trace = self.receive_packets(trace_connection)
            trace_connection.close()
            tcpdump.kill()

            self.logger.info('reading measurement info from client')
            client_side_info = MUtils.read_compressed_json(self.control_connection_fd)

            self.logger.info('sending trace statistics')
            trace_statistics = self.compute_trace_statistics(trace, trace_size)
            MUtils.send_json(self.control_connection_fd, trace_statistics)

            result = {}
            result['timestamp'] = timestamp 
            result['trace_id'] = trace_id
            result['trace_size'] = trace_size
            result['client_side_info'] = client_side_info
            result['statistics'] = trace_statistics
            result['server_address'] = {'IP': listen_address[0], 'port': listen_address[1]}
            result['client_address'] = {'IP': self.client_IP, 'port': client_port}
            result['trace_filename'] = os.path.basename(trace_filepath)
            result['pcap_filename'] = os.path.basename(pcap_filepath)

            self.save_received_trace(trace, result, trace_filepath)

            return result
        except (ValueError, socket.error, socket.timeout, zlib.error) as e:
            self.logger.error('read trace failed (%s)' % e)
            raise
        finally:
            # To be sure that the trace connection
            # gets closed even in case of errors
            if trace_connection: trace_connection.close()
Esempio n. 9
0
    def handle(self):
        if not self.server.can_start_measurement():
            self.logger.info('refusing connection, server is busy')
            self.fd.write(Config.MEASUREMENT_SERVER_BUSY_MSG + '\n')
            self.fd.flush()
            return
        try:
            self.fd.write(Config.MEASUREMENT_SERVER_AVAILABLE_MSG + '\n')
            self.fd.flush()

            self.client_info = self.read_client_info()
            self.logger.info('client id is %s' % self.client_info['device_info']['unique_id'])

            self.measurement_dir = self.create_measurement_dir(self.server.output_dir,
                                                               self.client_info,
                                                               self.start_time)
            self.logger.info('measurement results directory is %s' % self.measurement_dir)

            self.logger.info('running traceroute')
            self.traceroute = NetUtils.TraceRoute(self.client_address[0])
            self.traceroute.run()

            self.logger.info('receiving traceroute from client')
            self.remote_traceroute = MUtils.read_compressed_json(self.fd)

            self.logger.info('receiving traces')
            self.received_traces = []
            while True:
                mtype = self.fd.readline().strip()
                if not mtype:
                    raise socket.error('connection closed by remote host')
                elif mtype == Config.END_MEASUREMENTS:
                    self.logger.info('END_MEASUREMENTS received')
                    break
                elif mtype == Config.RTP_SEND_MEASUREMENT_TYPE:
                    handler = RTPTraceReceiver.RTPTraceReceiver(self.fd,
                                                                 self.request.getsockname(),
                                                                 self.client_address,
                                                                 self.measurement_dir)
                elif mtype == Config.RTP_RECV_MEASUREMENT_TYPE:
                    handler = RTPTraceSender.RTPTraceSender(self.fd,
                                                            self.request.getsockname(),
                                                            self.client_address,
                                                            self.measurement_dir)
                elif mtype == Config.RANDOM_SEND_MEASUREMENT_TYPE:
                    handler = RandomTraceReceiver.RandomTraceReceiver(self.fd,
                                                                      self.request.getsockname(),
                                                                      self.client_address,
                                                                      self.measurement_dir)
                elif mtype == Config.RANDOM_RECV_MEASUREMENT_TYPE:
                    handler = RandomTraceSender.RandomTraceSender(self.fd,
                                                                  self.request.getsockname(),
                                                                  self.client_address,
                                                                  self.measurement_dir)
                else:
                    raise ValueError('BUG: received unknown measurement type %s' % mtype)

                self.logger.info('starting measurement type %s' % mtype)
                measurement_info = handler.run()
                measurement_info['measurement_type'] = mtype
                self.received_traces.append(measurement_info)

            self.logger.info('receiving network statuses')
            self.network_statuses = MUtils.read_compressed_json(self.fd)

            self.logger.info('saving results')
            self.save_results()

        except (socket.error, socket.timeout) as e:
            self.logger.error('connection failed (%s)' % e)
        except zlib.error as e:
            self.logger.error('communication error (%s)' % e)
        except OSError as e:
            self.logger.error('internal error (%s)' % e)
        finally:
            self.server.measurement_has_finished()
Esempio n. 10
0
    def handle(self):
        if not self.server.can_start_measurement():
            self.logger.info('refusing connection, server is busy')
            self.fd.write(Config.MEASUREMENT_SERVER_BUSY_MSG + '\n')
            self.fd.flush()
            return
        try:
            self.fd.write(Config.MEASUREMENT_SERVER_AVAILABLE_MSG + '\n')
            self.fd.flush()

            self.client_info = self.read_client_info()
            self.logger.info('client id is %s' %
                             self.client_info['device_info']['unique_id'])

            self.measurement_dir = self.create_measurement_dir(
                self.server.output_dir, self.client_info, self.start_time)
            self.logger.info('measurement results directory is %s' %
                             self.measurement_dir)

            self.logger.info('running traceroute')
            self.traceroute = NetUtils.TraceRoute(self.client_address[0])
            self.traceroute.run()

            self.logger.info('receiving traceroute from client')
            self.remote_traceroute = MUtils.read_compressed_json(self.fd)

            self.logger.info('receiving traces')
            self.received_traces = []
            while True:
                mtype = self.fd.readline().strip()
                if not mtype:
                    raise socket.error('connection closed by remote host')
                elif mtype == Config.END_MEASUREMENTS:
                    self.logger.info('END_MEASUREMENTS received')
                    break
                elif mtype == Config.RTP_SEND_MEASUREMENT_TYPE:
                    handler = RTPTraceReceiver.RTPTraceReceiver(
                        self.fd, self.request.getsockname(),
                        self.client_address, self.measurement_dir)
                elif mtype == Config.RTP_RECV_MEASUREMENT_TYPE:
                    handler = RTPTraceSender.RTPTraceSender(
                        self.fd, self.request.getsockname(),
                        self.client_address, self.measurement_dir)
                elif mtype == Config.RANDOM_SEND_MEASUREMENT_TYPE:
                    handler = RandomTraceReceiver.RandomTraceReceiver(
                        self.fd, self.request.getsockname(),
                        self.client_address, self.measurement_dir)
                elif mtype == Config.RANDOM_RECV_MEASUREMENT_TYPE:
                    handler = RandomTraceSender.RandomTraceSender(
                        self.fd, self.request.getsockname(),
                        self.client_address, self.measurement_dir)
                else:
                    raise ValueError(
                        'BUG: received unknown measurement type %s' % mtype)

                self.logger.info('starting measurement type %s' % mtype)
                measurement_info = handler.run()
                measurement_info['measurement_type'] = mtype
                self.received_traces.append(measurement_info)

            self.logger.info('receiving network statuses')
            self.network_statuses = MUtils.read_compressed_json(self.fd)

            self.logger.info('saving results')
            self.save_results()

        except (socket.error, socket.timeout) as e:
            self.logger.error('connection failed (%s)' % e)
        except zlib.error as e:
            self.logger.error('communication error (%s)' % e)
        except OSError as e:
            self.logger.error('internal error (%s)' % e)
        finally:
            self.server.measurement_has_finished()