forked from naksyn/PythonMemoryModule
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpipe.py
More file actions
127 lines (99 loc) · 4.34 KB
/
pipe.py
File metadata and controls
127 lines (99 loc) · 4.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import windows
from windows import winproxy
import windows.generated_def as gdef
import ctypes
from windows.pycompat import is_py3
if is_py3:
from multiprocessing.connection import PipeConnection as native_PipeConnection
else:
from _multiprocessing import PipeConnection as native_PipeConnection
# Inspired from 'multiprocessing\connection.py'
def full_pipe_address(addr):
"""Return the full address of the pipe `addr`"""
if not isinstance(addr, bytes):
addr = addr.encode("ascii")
if addr.startswith(b"\\\\"):
return addr
return br"\\.\pipe" + "\\".encode() + addr
class PipeConnection(object): # Cannot inherit: crash the interpreter
"""A wrapper arround :class:`_multiprocessing.PipeConnection` able to work as a ContextManager"""
BUFFER_SIZE = 0x2000
def __init__(self, connection, name=None, server=False):
self.handle = connection.fileno()
self.connection = connection
self.name = name
self.server = server
@classmethod
def from_handle(cls, phandle, *args, **kwargs):
"""Create a :class:`PipeConnection` from pipe handle `phandle`"""
connection = native_PipeConnection(phandle)
return cls(connection, *args, **kwargs)
@classmethod
def create(cls, addr, security_descriptor=None):
"""Create a namedpipe pipe ``addr``
:returns type: :class:`PipeConnection`
"""
addr = full_pipe_address(addr)
security_attributes = None
if security_descriptor is not None:
if isinstance(security_descriptor, str):
security_descriptor = windows.security.SecurityDescriptor.from_string(security_descriptor)
security_attributes = gdef.SECURITY_ATTRIBUTES()
security_attributes.nLength = ctypes.sizeof(security_attributes)
security_attributes.lpSecurityDescriptor = security_descriptor # Accept as arg ?
security_attributes.bInheritHandle = True # Accept as arg ?
pipehandle = winproxy.CreateNamedPipeA(
addr, gdef.PIPE_ACCESS_DUPLEX,
gdef.PIPE_TYPE_MESSAGE | gdef.PIPE_READMODE_MESSAGE |
gdef.PIPE_WAIT,
gdef.PIPE_UNLIMITED_INSTANCES, cls.BUFFER_SIZE, cls.BUFFER_SIZE,
gdef.NMPWAIT_WAIT_FOREVER, security_attributes
)
return cls.from_handle(pipehandle, name=addr, server=True)
@classmethod
def connect(cls, addr):
"""Connect to the named pipe ``addr``
:returns type: :class:`PipeConnection`
"""
addr = full_pipe_address(addr)
pipehandle = winproxy.CreateFileA(addr, gdef.GENERIC_READ | gdef.GENERIC_WRITE, 0, None, gdef.OPEN_EXISTING, 0, None)
winproxy.SetNamedPipeHandleState(pipehandle, gdef.ULONG(gdef.PIPE_READMODE_MESSAGE), None, None)
return cls.from_handle(pipehandle, name=addr, server=False)
def send(self, *args, **kwargs):
"""Send an object on the pipe"""
return self.connection.send(*args, **kwargs)
def recv(self, *args, **kwargs):
"""Send an object from the pipe"""
return self.connection.recv(*args, **kwargs)
def wait_connection(self):
"""Wait for a client process to connect to the named pipe"""
return winproxy.ConnectNamedPipe(self.handle, None)
def get_security_descriptor(self):
return windows.security.SecurityDescriptor.from_handle(self.handle)
def set_security_descriptor(self, sd):
if isinstance(sd, basestring):
sd = windows.security.SecurityDescriptor.from_string(sd)
sd._apply_to_handle_and_type(self.handle)
security_descriptor = property(get_security_descriptor, set_security_descriptor)
def close(self):
"""Close the handle of the pipe"""
self.connection.close()
self.handle = None
def __enter__(self):
return self
def __exit__(self, *args, **kwargs):
self.close()
def __repr__(self):
return """<{0} name="{1}" server={2}>""".format(type(self).__name__, self.name, self.server)
connect = PipeConnection.connect
create = PipeConnection.create
def send_object(addr, obj):
"""Send `obj` on pipe ``addr``"""
with connect(addr) as np:
np.send(obj)
return None
def recv_object(addr):
"""Receive an object from pipe ``addr``"""
with create(addr) as np:
np.wait_connection()
return np.recv()