OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Constrained Network Server. Serves files with supplied network constraints. | 6 """Constrained Network Server. Serves files with supplied network constraints. |
7 | 7 |
8 The CNS exposes a web based API allowing network constraints to be imposed on | 8 The CNS exposes a web based API allowing network constraints to be imposed on |
9 file serving. | 9 file serving. |
10 | 10 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 """ | 125 """ |
126 kwargs['port'] = port | 126 kwargs['port'] = port |
127 try: | 127 try: |
128 cherrypy.log('Setting up port %d' % port) | 128 cherrypy.log('Setting up port %d' % port) |
129 traffic_control.CreateConstrainedPort(kwargs) | 129 traffic_control.CreateConstrainedPort(kwargs) |
130 return True | 130 return True |
131 except traffic_control.TrafficControlError as e: | 131 except traffic_control.TrafficControlError as e: |
132 cherrypy.log('Error: %s\nOutput: %s' % (e.msg, e.error)) | 132 cherrypy.log('Error: %s\nOutput: %s' % (e.msg, e.error)) |
133 return False | 133 return False |
134 | 134 |
135 def Cleanup(self, all_ports): | 135 def Cleanup(self, all_ports, request_ip=None): |
136 """Cleans up expired ports, or if all_ports=True, all allocated ports. | 136 """Cleans up expired ports, or if all_ports=True, all allocated ports. |
137 | 137 |
138 By default, ports which haven't been used for self._expiry_time_secs are | 138 By default, ports which haven't been used for self._expiry_time_secs are |
139 torn down. If all_ports=True then they are torn down regardless. | 139 torn down. If all_ports=True then they are torn down regardless. |
140 | 140 |
141 Args: | 141 Args: |
142 all_ports: Should all ports be torn down regardless of expiration? | 142 all_ports: Should all ports be torn down regardless of expiration? |
| 143 request_ip: Tear ports matching the IP address regarless of expiration. |
143 """ | 144 """ |
144 with self._port_lock: | 145 with self._port_lock: |
145 now = time.time() | 146 now = time.time() |
146 # Use .items() instead of .iteritems() so we can delete keys w/o error. | 147 # Use .items() instead of .iteritems() so we can delete keys w/o error. |
147 for port, status in self._ports.items(): | 148 for port, status in self._ports.items(): |
148 expired = now - status['last_update'] > self._expiry_time_secs | 149 expired = now - status['last_update'] > self._expiry_time_secs |
149 if all_ports or expired: | 150 matching_ip = request_ip and status['key'][0].startswith(request_ip) |
| 151 if all_ports or expired or matching_ip: |
150 cherrypy.log('Cleaning up port %d' % port) | 152 cherrypy.log('Cleaning up port %d' % port) |
151 self._DeletePort(port) | 153 self._DeletePort(port) |
152 del self._ports[port] | 154 del self._ports[port] |
153 | 155 |
154 def _DeletePort(self, port): | 156 def _DeletePort(self, port): |
155 """Deletes network constraints on port. | 157 """Deletes network constraints on port. |
156 | 158 |
157 Args: | 159 Args: |
158 port: The port number associated with the network constraints. | 160 port: The port number associated with the network constraints. |
159 """ | 161 """ |
(...skipping 10 matching lines...) Expand all Loading... |
170 """Sets up initial state for the CNS. | 172 """Sets up initial state for the CNS. |
171 | 173 |
172 Args: | 174 Args: |
173 options: optparse based class returned by ParseArgs() | 175 options: optparse based class returned by ParseArgs() |
174 port_allocator: A port allocator instance. | 176 port_allocator: A port allocator instance. |
175 """ | 177 """ |
176 self._options = options | 178 self._options = options |
177 self._port_allocator = port_allocator | 179 self._port_allocator = port_allocator |
178 | 180 |
179 @cherrypy.expose | 181 @cherrypy.expose |
| 182 def Cleanup(self): |
| 183 """Cleans up all the ports allocated using the request IP address. |
| 184 |
| 185 When requesting a constrained port, the cherrypy.request.remote.ip is used |
| 186 as a key for that port (in addition to other request parameters). Such |
| 187 ports created for the same IP address are removed. |
| 188 """ |
| 189 cherrypy.log('Cleaning up ports allocated by %s.' % |
| 190 cherrypy.request.remote.ip) |
| 191 self._port_allocator.Cleanup(all_ports=False, |
| 192 request_ip=cherrypy.request.remote.ip) |
| 193 |
| 194 @cherrypy.expose |
180 def ServeConstrained(self, f=None, bandwidth=None, latency=None, loss=None, | 195 def ServeConstrained(self, f=None, bandwidth=None, latency=None, loss=None, |
181 new_port=False, no_cache=False, **kwargs): | 196 new_port=False, no_cache=False, **kwargs): |
182 """Serves the requested file with the requested constraints. | 197 """Serves the requested file with the requested constraints. |
183 | 198 |
184 Subsequent requests for the same constraints from the same IP will share the | 199 Subsequent requests for the same constraints from the same IP will share the |
185 previously created port unless new_port equals True. If no constraints | 200 previously created port unless new_port equals True. If no constraints |
186 are provided the file is served as is. | 201 are provided the file is served as is. |
187 | 202 |
188 Args: | 203 Args: |
189 f: path relative to http root of file to serve. | 204 f: path relative to http root of file to serve. |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 try: | 448 try: |
434 cherrypy.quickstart(ConstrainedNetworkServer(options, pa)) | 449 cherrypy.quickstart(ConstrainedNetworkServer(options, pa)) |
435 finally: | 450 finally: |
436 # Disable Ctrl-C handler to prevent interruption of cleanup. | 451 # Disable Ctrl-C handler to prevent interruption of cleanup. |
437 signal.signal(signal.SIGINT, lambda signal, frame: None) | 452 signal.signal(signal.SIGINT, lambda signal, frame: None) |
438 pa.Cleanup(all_ports=True) | 453 pa.Cleanup(all_ports=True) |
439 | 454 |
440 | 455 |
441 if __name__ == '__main__': | 456 if __name__ == '__main__': |
442 Main() | 457 Main() |
OLD | NEW |