# Copyright (c) 2013 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import logging import os import shutil from autotest_lib.client.common_lib import error, utils from autotest_lib.client.common_lib.cros import avahi_utils from autotest_lib.client.cros import service_stopper, tcpdump P2P_SHARE_PATH = '/var/cache/p2p' # A path used to store the existing p2p files during the test and restore them # once the test finishes. P2P_SHARE_BACKUP_PATH = '/var/cache/p2p-backup' def p2p_backup_files(backup_path=P2P_SHARE_BACKUP_PATH): """Backup the P2P shared files and create an empty shared directory. p2p-server shall not be running during backup or restore. @param backup_path: The path where the files will be moved to. @raise error.TestError """ try: if os.path.exists(backup_path): shutil.rmtree(backup_path) if os.path.exists(P2P_SHARE_PATH): os.rename(P2P_SHARE_PATH, backup_path) except OSError, e: raise error.TestError("Error on P2P files backup: %s" % (e.message)) def p2p_restore_files(backup_path=P2P_SHARE_BACKUP_PATH): """Restore the P2P shared files from a backup and *delete* the backup. p2p-server shall not be running during backup or restore. @param backup_path: The path where the files will be moved from. """ if os.path.exists(P2P_SHARE_PATH): shutil.rmtree(P2P_SHARE_PATH, ignore_errors=True) if os.path.exists(backup_path): os.rename(backup_path, P2P_SHARE_PATH) class P2PServerOverTap(object): """Manage a p2p-server instance running over a TAP interface. This class manages a p2p-server instance configured to run over a TAP interface, useful for any test that needs to interact with the p2p-server (and its p2p-http-server instance) on a controled network environment. """ def __init__(self, tap_ip='169.254.10.1', tap_mask=24, tap_name='faketap'): """Initialize the configuration. @param tap_ip: IPv4 address for the TAP interface on the DUT's end. @param tap_mask: Network mask fot the tap_ip address. @param tap_name: The name prefix for the TAP interface. """ # The network 169.254/16 shouldn't clash with other real services and we # use a /24 subnet of it as the default safe value here. self._tap_ip = tap_ip self._tap_mask = tap_mask self._tap_name = tap_name self._services = None self.tap = None self._tcpdump = None def setup(self, dumpdir=None): """Initializes avahi daemon on a new tap interface. @param dumpdir: Directory where the traffic on the new tap interface is recorded. A value of None disables traffic dumping. """ try: from lansim import tuntap except ImportError: logging.exception('Failed to import lansim.') raise error.TestError('Error importing lansim. Did you setup_dep ' 'and install_pkg lansim on your test?') # Ensure p2p and avahi aren't running. self._services = service_stopper.ServiceStopper(['p2p', 'avahi']) self._services.stop_services() # Backup p2p files. p2p_backup_files() # Initialize the TAP interface. self.tap = tuntap.TunTap(tuntap.IFF_TAP, name=self._tap_name) self.tap.set_addr(self._tap_ip, self._tap_mask) self.tap.up() # Enable traffic dump. if not dumpdir is None: dumpfile = os.path.join(dumpdir, 'dump-%s.pcap' % self.tap.name) self._tcpdump = tcpdump.Tcpdump(self.tap.name, dumpfile) # Re-launch avahi-daemon on the TAP interface only. avahi_utils.avahi_start_on_iface(self.tap.name) utils.system("start p2p") def cleanup(self): """Restore the original environment as before the call to setup(). This method makes a best-effort attempt to restore the environment and logs all the errors encountered but doesn't fail. """ try: utils.system('stop p2p') avahi_utils.avahi_stop() except: logging.exception('Failed to stop tested services.') if self._tcpdump: self._tcpdump.stop() if self.tap: self.tap.down() # Restore p2p files. try: p2p_restore_files() except OSError: logging.exception('Failed to restore the P2P backup.') if self._services: self._services.restore_services()