Class representing a pipe server. This is much like a bound, listening socket.
| 245 | |
| 246 | |
| 247 | class PipeServer(object): |
| 248 | """Class representing a pipe server. |
| 249 | |
| 250 | This is much like a bound, listening socket. |
| 251 | """ |
| 252 | def __init__(self, address): |
| 253 | self._address = address |
| 254 | self._free_instances = weakref.WeakSet() |
| 255 | # initialize the pipe attribute before calling _server_pipe_handle() |
| 256 | # because this function can raise an exception and the destructor calls |
| 257 | # the close() method |
| 258 | self._pipe = None |
| 259 | self._accept_pipe_future = None |
| 260 | self._pipe = self._server_pipe_handle(True) |
| 261 | |
| 262 | def _get_unconnected_pipe(self): |
| 263 | # Create new instance and return previous one. This ensures |
| 264 | # that (until the server is closed) there is always at least |
| 265 | # one pipe handle for address. Therefore if a client attempt |
| 266 | # to connect it will not fail with FileNotFoundError. |
| 267 | tmp, self._pipe = self._pipe, self._server_pipe_handle(False) |
| 268 | return tmp |
| 269 | |
| 270 | def _server_pipe_handle(self, first): |
| 271 | # Return a wrapper for a new pipe handle. |
| 272 | if self.closed(): |
| 273 | return None |
| 274 | flags = _winapi.PIPE_ACCESS_DUPLEX | _winapi.FILE_FLAG_OVERLAPPED |
| 275 | if first: |
| 276 | flags |= _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE |
| 277 | h = _winapi.CreateNamedPipe( |
| 278 | self._address, flags, |
| 279 | _winapi.PIPE_TYPE_MESSAGE | _winapi.PIPE_READMODE_MESSAGE | |
| 280 | _winapi.PIPE_WAIT, |
| 281 | _winapi.PIPE_UNLIMITED_INSTANCES, |
| 282 | windows_utils.BUFSIZE, windows_utils.BUFSIZE, |
| 283 | _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL) |
| 284 | pipe = windows_utils.PipeHandle(h) |
| 285 | self._free_instances.add(pipe) |
| 286 | return pipe |
| 287 | |
| 288 | def closed(self): |
| 289 | return (self._address is None) |
| 290 | |
| 291 | def close(self): |
| 292 | if self._accept_pipe_future is not None: |
| 293 | self._accept_pipe_future.cancel() |
| 294 | self._accept_pipe_future = None |
| 295 | # Close all instances which have not been connected to by a client. |
| 296 | if self._address is not None: |
| 297 | for pipe in self._free_instances: |
| 298 | pipe.close() |
| 299 | self._pipe = None |
| 300 | self._address = None |
| 301 | self._free_instances.clear() |
| 302 | |
| 303 | __del__ = close |
| 304 |
no outgoing calls
no test coverage detected
searching dependent graphs…