@@ -53,14 +53,15 @@ def _stop(self, proc, *, timeout=None):
53
53
)
54
54
55
55
@Driver .check_active
56
- @step (args = ["filename" , "count" ])
57
- def start_record (self , filename , * , count = None ):
56
+ @step (args = ["filename" , "count" , "timeout" ])
57
+ def start_record (self , filename , * , count = None , timeout = None ):
58
58
"""
59
59
Starts tcpdump on bound network interface resource.
60
60
61
61
Args:
62
- filename (str): name of a file to record to
62
+ filename (str): name of a file to record to, or None to record to stdout
63
63
count (int): optional, exit after receiving this many number of packets
64
+ timeout (int): optional, number of seconds to capture packets before tcpdump exits
64
65
Returns:
65
66
Popen object of tcpdump process
66
67
"""
@@ -69,9 +70,15 @@ def start_record(self, filename, *, count=None):
69
70
cmd = ["tcpdump" , self .iface .ifname ]
70
71
if count is not None :
71
72
cmd .append (str (count ))
73
+ if timeout is not None :
74
+ cmd .append ("--timeout" )
75
+ cmd .append (str (timeout ))
72
76
cmd = self ._wrap_command (cmd )
73
- with open (filename , "wb" ) as outdata :
74
- self ._record_handle = subprocess .Popen (cmd , stdout = outdata , stderr = subprocess .PIPE )
77
+ if filename is None :
78
+ self ._record_handle = subprocess .Popen (cmd , stdout = subprocess .PIPE )
79
+ else :
80
+ with open (filename , "wb" ) as outdata :
81
+ self ._record_handle = subprocess .Popen (cmd , stdout = outdata , stderr = subprocess .PIPE )
75
82
return self ._record_handle
76
83
77
84
@Driver .check_active
@@ -86,6 +93,11 @@ def stop_record(self, *, timeout=None):
86
93
"""
87
94
try :
88
95
self ._stop (self ._record_handle , timeout = timeout )
96
+ except subprocess .TimeoutExpired :
97
+ # If live streaming packets, there is no reason to wait for tcpdump
98
+ # to finish, so expect a timeout if piping to stdout
99
+ if self ._record_handle .stdout is None :
100
+ raise
89
101
finally :
90
102
self ._record_handle = None
91
103
@@ -97,17 +109,18 @@ def record(self, filename, *, count=None, timeout=None):
97
109
Either count or timeout must be specified.
98
110
99
111
Args:
100
- filename (str): name of a file to record to
112
+ filename (str): name of a file to record to, or None to live stream packets
101
113
count (int): optional, exit after receiving this many number of packets
102
- timeout (int): optional, maximum number of seconds to wait for the tcpdump process to
103
- terminate
114
+ timeout (int): optional, number of seconds to capture packets before tcpdump exits
115
+ Returns:
116
+ Popen object of tcpdump process. If filename is None, packets can be read from stdout
104
117
"""
105
118
assert count or timeout
106
119
107
120
try :
108
- yield self .start_record (filename , count = count )
121
+ yield self .start_record (filename , count = count , timeout = timeout )
109
122
finally :
110
- self .stop_record (timeout = timeout )
123
+ self .stop_record (timeout = 0 if filename is None else None )
111
124
112
125
@Driver .check_active
113
126
@step (args = ["filename" ])
@@ -170,12 +183,7 @@ def get_statistics(self):
170
183
"""
171
184
Returns basic interface statistics of bound network interface resource.
172
185
"""
173
- cmd = self .iface .command_prefix + [
174
- "ip" ,
175
- "--json" ,
176
- "-stats" , "-stats" ,
177
- "link" , "show" ,
178
- self .iface .ifname ]
186
+ cmd = self .iface .command_prefix + ["ip" , "--json" , "-stats" , "-stats" , "link" , "show" , self .iface .ifname ]
179
187
output = processwrapper .check_output (cmd )
180
188
return json .loads (output )[0 ]
181
189
0 commit comments