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