ronnie
2022-10-14 1504bb53e29d3d46222c0b3ea994fc494b48e153
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# 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 subprocess
 
from autotest_lib.client.bin import utils
 
class Tcpdump(object):
    """tcpdump capture process wrapper."""
 
    def __init__(self, iface, dumpfilename):
        """Launches a tcpdump process on the background.
 
        @param iface: The name of the interface to listen on.
        @param dumpfilename: The filename of the destination dump file.
        @raise utils.TimeoutError if tcpdump fails to start after 10 seconds.
        """
        logging.debug('Recording %s traffic to %s.', iface, dumpfilename)
        # Force to run tcpdump as root, since the dump file is created *after*
        # the process drops to a unprivileged user, meaning that it can't create
        # the passed dumpfilename file.
        self._tcpdump_proc = subprocess.Popen(
                ['tcpdump', '-i', iface, '-w', dumpfilename, '-Z', 'root'],
                stdout=open('/dev/null', 'w'),
                stderr=subprocess.STDOUT)
        # Wait for tcpdump to initialize and create the dump file.
        utils.poll_for_condition(
                lambda: os.path.exists(dumpfilename),
                desc='tcpdump creates the dump file.',
                sleep_interval=1,
                timeout=10.)
 
 
    def stop(self, timeout=10.):
        """Stop the dump process and wait for it to return.
 
        This method stops the tcpdump process running in background and waits
        for it to finish for a given timeout.
        @param timeout: The time to wait for the tcpdump to finish in seconds.
                        None means no timeout.
        @return whether the tcpdump is not running.
        """
        if not self._tcpdump_proc:
            return True
 
        # Send SIGTERM to tcpdump.
        try:
            self._tcpdump_proc.terminate()
        except OSError, e:
            # If the process exits before we can send it a SIGTERM, an
            # OSError exception is raised here which we can ignore since the
            # process already finished.
            logging.error('Trying to kill tcpdump (%d): %s',
                          self._tcpdump_proc.pid, e.strerror)
 
        logging.debug('Waiting for pid %d to finish.', self._tcpdump_proc.pid)
        if timeout is None:
            self._tcpdump_proc.wait()
        else:
            try:
                utils.poll_for_condition(
                        lambda: not self._tcpdump_proc.poll() is None,
                        sleep_interval=1,
                        timeout=timeout)
            except utils.TimeoutError:
                logging.error('tcpdump failed to finish after %f seconds. Dump '
                              'file can be truncated.', timeout)
                return False
 
        self._tcpdump_proc = None
        return True
 
 
    def __del__(self):
        self.stop()