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')
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')
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')
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
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
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()
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()
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()
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()
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()