@@ -53,14 +53,15 @@ def _stop(self, proc, *, timeout=None):
5353 )
5454
5555 @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 ):
5858 """
5959 Starts tcpdump on bound network interface resource.
6060
6161 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
6363 count (int): optional, exit after receiving this many number of packets
64+ timeout (int): optional, number of seconds to capture packets before tcpdump exits
6465 Returns:
6566 Popen object of tcpdump process
6667 """
@@ -69,9 +70,15 @@ def start_record(self, filename, *, count=None):
6970 cmd = ["tcpdump" , self .iface .ifname ]
7071 if count is not None :
7172 cmd .append (str (count ))
73+ if timeout is not None :
74+ cmd .append ("--timeout" )
75+ cmd .append (str (timeout ))
7276 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 )
7582 return self ._record_handle
7683
7784 @Driver .check_active
@@ -86,6 +93,11 @@ def stop_record(self, *, timeout=None):
8693 """
8794 try :
8895 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
89101 finally :
90102 self ._record_handle = None
91103
@@ -97,17 +109,18 @@ def record(self, filename, *, count=None, timeout=None):
97109 Either count or timeout must be specified.
98110
99111 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
101113 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
104117 """
105118 assert count or timeout
106119
107120 try :
108- yield self .start_record (filename , count = count )
121+ yield self .start_record (filename , count = count , timeout = timeout )
109122 finally :
110- self .stop_record (timeout = timeout )
123+ self .stop_record (timeout = 0 if filename is None else None )
111124
112125 @Driver .check_active
113126 @step (args = ["filename" ])
@@ -170,12 +183,7 @@ def get_statistics(self):
170183 """
171184 Returns basic interface statistics of bound network interface resource.
172185 """
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 ]
179187 output = processwrapper .check_output (cmd )
180188 return json .loads (output )[0 ]
181189
0 commit comments