dbus-fast 2.45.0__cp39-cp39-musllinux_1_2_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dbus_fast/__init__.py +82 -0
- dbus_fast/__version__.py +10 -0
- dbus_fast/_private/__init__.py +1 -0
- dbus_fast/_private/_cython_compat.py +14 -0
- dbus_fast/_private/address.cpython-39-aarch64-linux-gnu.so +0 -0
- dbus_fast/_private/address.pxd +15 -0
- dbus_fast/_private/address.py +117 -0
- dbus_fast/_private/constants.py +20 -0
- dbus_fast/_private/marshaller.cpython-39-aarch64-linux-gnu.so +0 -0
- dbus_fast/_private/marshaller.pxd +110 -0
- dbus_fast/_private/marshaller.py +228 -0
- dbus_fast/_private/unmarshaller.cpython-39-aarch64-linux-gnu.so +0 -0
- dbus_fast/_private/unmarshaller.pxd +261 -0
- dbus_fast/_private/unmarshaller.py +902 -0
- dbus_fast/_private/util.py +176 -0
- dbus_fast/aio/__init__.py +5 -0
- dbus_fast/aio/message_bus.py +578 -0
- dbus_fast/aio/message_reader.cpython-39-aarch64-linux-gnu.so +0 -0
- dbus_fast/aio/message_reader.pxd +13 -0
- dbus_fast/aio/message_reader.py +49 -0
- dbus_fast/aio/proxy_object.py +207 -0
- dbus_fast/auth.py +126 -0
- dbus_fast/constants.py +152 -0
- dbus_fast/errors.py +84 -0
- dbus_fast/glib/__init__.py +3 -0
- dbus_fast/glib/message_bus.py +515 -0
- dbus_fast/glib/proxy_object.py +319 -0
- dbus_fast/introspection.py +683 -0
- dbus_fast/message.cpython-39-aarch64-linux-gnu.so +0 -0
- dbus_fast/message.pxd +76 -0
- dbus_fast/message.py +387 -0
- dbus_fast/message_bus.cpython-39-aarch64-linux-gnu.so +0 -0
- dbus_fast/message_bus.pxd +75 -0
- dbus_fast/message_bus.py +1310 -0
- dbus_fast/proxy_object.py +358 -0
- dbus_fast/py.typed +0 -0
- dbus_fast/send_reply.py +61 -0
- dbus_fast/service.cpython-39-aarch64-linux-gnu.so +0 -0
- dbus_fast/service.pxd +50 -0
- dbus_fast/service.py +682 -0
- dbus_fast/signature.cpython-39-aarch64-linux-gnu.so +0 -0
- dbus_fast/signature.pxd +31 -0
- dbus_fast/signature.py +481 -0
- dbus_fast/unpack.cpython-39-aarch64-linux-gnu.so +0 -0
- dbus_fast/unpack.pxd +13 -0
- dbus_fast/unpack.py +24 -0
- dbus_fast/validators.py +199 -0
- dbus_fast-2.45.0.dist-info/METADATA +263 -0
- dbus_fast-2.45.0.dist-info/RECORD +51 -0
- dbus_fast-2.45.0.dist-info/WHEEL +4 -0
- dbus_fast-2.45.0.dist-info/licenses/LICENSE +22 -0
|
@@ -0,0 +1,902 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import array
|
|
4
|
+
import errno
|
|
5
|
+
import io
|
|
6
|
+
import socket
|
|
7
|
+
import sys
|
|
8
|
+
from collections.abc import Iterable
|
|
9
|
+
from struct import Struct
|
|
10
|
+
from typing import TYPE_CHECKING, Any, Callable
|
|
11
|
+
|
|
12
|
+
from ..constants import MESSAGE_FLAG_MAP, MESSAGE_TYPE_MAP, MessageFlag
|
|
13
|
+
from ..errors import InvalidMessageError
|
|
14
|
+
from ..message import Message
|
|
15
|
+
from ..signature import SignatureType, Variant, get_signature_tree
|
|
16
|
+
from .constants import BIG_ENDIAN, LITTLE_ENDIAN, PROTOCOL_VERSION
|
|
17
|
+
|
|
18
|
+
MESSAGE_FLAG_INTENUM = MessageFlag
|
|
19
|
+
|
|
20
|
+
MAX_UNIX_FDS = 16
|
|
21
|
+
MAX_UNIX_FDS_SIZE = array.array("i").itemsize
|
|
22
|
+
UNIX_FDS_CMSG_LENGTH = socket.CMSG_LEN(MAX_UNIX_FDS_SIZE * MAX_UNIX_FDS)
|
|
23
|
+
|
|
24
|
+
UNPACK_SYMBOL = {LITTLE_ENDIAN: "<", BIG_ENDIAN: ">"}
|
|
25
|
+
|
|
26
|
+
UINT32_CAST = "I"
|
|
27
|
+
UINT32_SIZE = 4
|
|
28
|
+
UINT32_DBUS_TYPE = "u"
|
|
29
|
+
|
|
30
|
+
INT16_CAST = "h"
|
|
31
|
+
INT16_SIZE = 2
|
|
32
|
+
INT16_DBUS_TYPE = "n"
|
|
33
|
+
|
|
34
|
+
UINT16_CAST = "H"
|
|
35
|
+
UINT16_SIZE = 2
|
|
36
|
+
UINT16_DBUS_TYPE = "q"
|
|
37
|
+
|
|
38
|
+
SYS_IS_LITTLE_ENDIAN = sys.byteorder == "little"
|
|
39
|
+
SYS_IS_BIG_ENDIAN = sys.byteorder == "big"
|
|
40
|
+
|
|
41
|
+
DBUS_TO_CTYPE = {
|
|
42
|
+
"y": ("B", 1), # byte
|
|
43
|
+
INT16_DBUS_TYPE: (INT16_CAST, INT16_SIZE), # int16
|
|
44
|
+
UINT16_DBUS_TYPE: (UINT16_CAST, UINT16_SIZE), # uint16
|
|
45
|
+
"i": ("i", 4), # int32
|
|
46
|
+
UINT32_DBUS_TYPE: (UINT32_CAST, UINT32_SIZE), # uint32
|
|
47
|
+
"x": ("q", 8), # int64
|
|
48
|
+
"t": ("Q", 8), # uint64
|
|
49
|
+
"d": ("d", 8), # double
|
|
50
|
+
"h": (UINT32_CAST, UINT32_SIZE), # uint32
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
UNPACK_HEADER_LITTLE_ENDIAN = Struct("<III").unpack_from
|
|
54
|
+
UNPACK_HEADER_BIG_ENDIAN = Struct(">III").unpack_from
|
|
55
|
+
|
|
56
|
+
UINT32_UNPACK_LITTLE_ENDIAN = Struct(f"<{UINT32_CAST}").unpack_from
|
|
57
|
+
UINT32_UNPACK_BIG_ENDIAN = Struct(f">{UINT32_CAST}").unpack_from
|
|
58
|
+
|
|
59
|
+
INT16_UNPACK_LITTLE_ENDIAN = Struct(f"<{INT16_CAST}").unpack_from
|
|
60
|
+
INT16_UNPACK_BIG_ENDIAN = Struct(f">{INT16_CAST}").unpack_from
|
|
61
|
+
|
|
62
|
+
UINT16_UNPACK_LITTLE_ENDIAN = Struct(f"<{UINT16_CAST}").unpack_from
|
|
63
|
+
UINT16_UNPACK_BIG_ENDIAN = Struct(f">{UINT16_CAST}").unpack_from
|
|
64
|
+
|
|
65
|
+
HEADER_SIGNATURE_SIZE = 16
|
|
66
|
+
HEADER_ARRAY_OF_STRUCT_SIGNATURE_POSITION = 12
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Most common signatures
|
|
70
|
+
|
|
71
|
+
SIGNATURE_TREE_EMPTY = get_signature_tree("")
|
|
72
|
+
SIGNATURE_TREE_B = get_signature_tree("b")
|
|
73
|
+
SIGNATURE_TREE_N = get_signature_tree("n")
|
|
74
|
+
SIGNATURE_TREE_S = get_signature_tree("s")
|
|
75
|
+
SIGNATURE_TREE_O = get_signature_tree("o")
|
|
76
|
+
SIGNATURE_TREE_U = get_signature_tree("u")
|
|
77
|
+
SIGNATURE_TREE_Y = get_signature_tree("y")
|
|
78
|
+
|
|
79
|
+
SIGNATURE_TREE_AY = get_signature_tree("ay")
|
|
80
|
+
SIGNATURE_TREE_AS = get_signature_tree("as")
|
|
81
|
+
SIGNATURE_TREE_AS_TYPES_0 = SIGNATURE_TREE_AS.root_type
|
|
82
|
+
SIGNATURE_TREE_A_SV = get_signature_tree("a{sv}")
|
|
83
|
+
SIGNATURE_TREE_A_SV_TYPES_0 = SIGNATURE_TREE_A_SV.root_type
|
|
84
|
+
|
|
85
|
+
SIGNATURE_TREE_AO = get_signature_tree("ao")
|
|
86
|
+
SIGNATURE_TREE_AO_TYPES_0 = SIGNATURE_TREE_AO.root_type
|
|
87
|
+
|
|
88
|
+
SIGNATURE_TREE_OAS = get_signature_tree("oas")
|
|
89
|
+
SIGNATURE_TREE_OAS_TYPES_1 = SIGNATURE_TREE_OAS.types[1]
|
|
90
|
+
|
|
91
|
+
SIGNATURE_TREE_AY_TYPES_0 = SIGNATURE_TREE_AY.root_type
|
|
92
|
+
SIGNATURE_TREE_A_QV = get_signature_tree("a{qv}")
|
|
93
|
+
SIGNATURE_TREE_A_QV_TYPES_0 = SIGNATURE_TREE_A_QV.root_type
|
|
94
|
+
|
|
95
|
+
SIGNATURE_TREE_SA_SV_AS = get_signature_tree("sa{sv}as")
|
|
96
|
+
SIGNATURE_TREE_SA_SV_AS_TYPES_1 = SIGNATURE_TREE_SA_SV_AS.types[1]
|
|
97
|
+
SIGNATURE_TREE_SA_SV_AS_TYPES_2 = SIGNATURE_TREE_SA_SV_AS.types[2]
|
|
98
|
+
|
|
99
|
+
SIGNATURE_TREE_OA_SA_SV = get_signature_tree("oa{sa{sv}}")
|
|
100
|
+
SIGNATURE_TREE_OA_SA_SV_TYPES_1 = SIGNATURE_TREE_OA_SA_SV.types[1]
|
|
101
|
+
|
|
102
|
+
SIGNATURE_TREE_A_OA_SA_SV = get_signature_tree("a{oa{sa{sv}}}")
|
|
103
|
+
SIGNATURE_TREE_A_OA_SA_SV_TYPES_0 = SIGNATURE_TREE_A_OA_SA_SV.root_type
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
TOKEN_B_AS_INT = ord("b")
|
|
107
|
+
TOKEN_U_AS_INT = ord("u")
|
|
108
|
+
TOKEN_Y_AS_INT = ord("y")
|
|
109
|
+
TOKEN_A_AS_INT = ord("a")
|
|
110
|
+
TOKEN_O_AS_INT = ord("o")
|
|
111
|
+
TOKEN_S_AS_INT = ord("s")
|
|
112
|
+
TOKEN_G_AS_INT = ord("g")
|
|
113
|
+
TOKEN_N_AS_INT = ord("n")
|
|
114
|
+
TOKEN_X_AS_INT = ord("x")
|
|
115
|
+
TOKEN_T_AS_INT = ord("t")
|
|
116
|
+
TOKEN_D_AS_INT = ord("d")
|
|
117
|
+
TOKEN_Q_AS_INT = ord("q")
|
|
118
|
+
TOKEN_V_AS_INT = ord("v")
|
|
119
|
+
TOKEN_LEFT_CURLY_AS_INT = ord("{")
|
|
120
|
+
TOKEN_LEFT_PAREN_AS_INT = ord("(")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
VARIANT_BOOL_TRUE = Variant._factory(SIGNATURE_TREE_B, True)
|
|
124
|
+
VARIANT_BOOL_FALSE = Variant._factory(SIGNATURE_TREE_B, False)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
ARRAY = array.array
|
|
128
|
+
SOL_SOCKET = socket.SOL_SOCKET
|
|
129
|
+
SCM_RIGHTS = socket.SCM_RIGHTS
|
|
130
|
+
|
|
131
|
+
EAGAIN = errno.EAGAIN
|
|
132
|
+
EWOULDBLOCK = errno.EWOULDBLOCK
|
|
133
|
+
|
|
134
|
+
HEADER_IDX_TO_ARG_NAME = [
|
|
135
|
+
"",
|
|
136
|
+
"path",
|
|
137
|
+
"interface",
|
|
138
|
+
"member",
|
|
139
|
+
"error_name",
|
|
140
|
+
"reply_serial",
|
|
141
|
+
"destination",
|
|
142
|
+
"sender",
|
|
143
|
+
"signature",
|
|
144
|
+
"unix_fds",
|
|
145
|
+
]
|
|
146
|
+
HEADER_PATH_IDX = HEADER_IDX_TO_ARG_NAME.index("path")
|
|
147
|
+
HEADER_INTERFACE_IDX = HEADER_IDX_TO_ARG_NAME.index("interface")
|
|
148
|
+
HEADER_MEMBER_IDX = HEADER_IDX_TO_ARG_NAME.index("member")
|
|
149
|
+
HEADER_ERROR_NAME_IDX = HEADER_IDX_TO_ARG_NAME.index("error_name")
|
|
150
|
+
HEADER_REPLY_SERIAL_IDX = HEADER_IDX_TO_ARG_NAME.index("reply_serial")
|
|
151
|
+
HEADER_DESTINATION_IDX = HEADER_IDX_TO_ARG_NAME.index("destination")
|
|
152
|
+
HEADER_SENDER_IDX = HEADER_IDX_TO_ARG_NAME.index("sender")
|
|
153
|
+
HEADER_SIGNATURE_IDX = HEADER_IDX_TO_ARG_NAME.index("signature")
|
|
154
|
+
HEADER_UNIX_FDS_IDX = HEADER_IDX_TO_ARG_NAME.index("unix_fds")
|
|
155
|
+
|
|
156
|
+
_EMPTY_HEADERS: list[Any | None] = [None] * len(HEADER_IDX_TO_ARG_NAME)
|
|
157
|
+
|
|
158
|
+
_SignatureType = SignatureType
|
|
159
|
+
_int = int
|
|
160
|
+
|
|
161
|
+
READER_TYPE = Callable[["Unmarshaller", SignatureType], Any]
|
|
162
|
+
|
|
163
|
+
MARSHALL_STREAM_END_ERROR = BlockingIOError
|
|
164
|
+
|
|
165
|
+
DEFAULT_BUFFER_SIZE = io.DEFAULT_BUFFER_SIZE
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def unpack_parser_factory(unpack_from: Callable, size: int) -> READER_TYPE:
|
|
169
|
+
"""Build a parser that unpacks the bytes using the given unpack_from function."""
|
|
170
|
+
|
|
171
|
+
def _unpack_from_parser(self: Unmarshaller, signature: SignatureType) -> Any:
|
|
172
|
+
self._pos += size + (-self._pos & (size - 1)) # align
|
|
173
|
+
return unpack_from(self._buf, self._pos - size)[0]
|
|
174
|
+
|
|
175
|
+
return _unpack_from_parser
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def build_simple_parsers(
|
|
179
|
+
endian: int,
|
|
180
|
+
) -> dict[str, Callable[[Unmarshaller, SignatureType], Any]]:
|
|
181
|
+
"""Build a dict of parsers for simple types."""
|
|
182
|
+
parsers: dict[str, READER_TYPE] = {}
|
|
183
|
+
for dbus_type, ctype_size in DBUS_TO_CTYPE.items():
|
|
184
|
+
ctype, size = ctype_size
|
|
185
|
+
size = ctype_size[1]
|
|
186
|
+
parsers[dbus_type] = unpack_parser_factory(
|
|
187
|
+
Struct(f"{UNPACK_SYMBOL[endian]}{ctype}").unpack_from, size
|
|
188
|
+
)
|
|
189
|
+
return parsers
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
try:
|
|
193
|
+
import cython
|
|
194
|
+
except ImportError:
|
|
195
|
+
from ._cython_compat import FAKE_CYTHON as cython
|
|
196
|
+
int_ = int
|
|
197
|
+
bytearray_ = bytearray
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def is_compiled() -> bool:
|
|
201
|
+
return cython.compiled
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _ustr_uint32(buf: bytearray_, pos: int_, endian: int_) -> int_:
|
|
205
|
+
if endian == LITTLE_ENDIAN:
|
|
206
|
+
return (
|
|
207
|
+
buf[pos] | (buf[pos + 1] << 8) | (buf[pos + 2] << 16) | (buf[pos + 3] << 24)
|
|
208
|
+
)
|
|
209
|
+
return buf[pos + 3] | (buf[pos + 2] << 8) | (buf[pos + 1] << 16) | (buf[pos] << 24)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def buffer_to_uint32(buf: bytearray, pos: int, endian: int) -> int:
|
|
213
|
+
return _ustr_uint32(buf, pos, endian)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _ustr_int16(buf: bytearray_, pos: int_, endian: int_) -> int_:
|
|
217
|
+
# Caution: this function will only work with Cython
|
|
218
|
+
# because it relies on casting the result to a signed int
|
|
219
|
+
# and will return an unsigned int if not compiled.
|
|
220
|
+
if endian == LITTLE_ENDIAN:
|
|
221
|
+
return buf[pos] | (buf[pos + 1] << 8) # pragma: no cover
|
|
222
|
+
return buf[pos + 1] | (buf[pos] << 8) # pragma: no cover
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def buffer_to_int16(buf: bytearray | bytes, pos: int, endian: int) -> int:
|
|
226
|
+
# Caution: this function will only work with Cython
|
|
227
|
+
# because it relies on casting the result to a signed int
|
|
228
|
+
# and will return an unsigned int if not compiled.
|
|
229
|
+
return _ustr_int16(buf, pos, endian)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _ustr_uint16(buf: bytearray_, pos: int_, endian: int_) -> int_:
|
|
233
|
+
if endian == LITTLE_ENDIAN:
|
|
234
|
+
return buf[pos] | (buf[pos + 1] << 8)
|
|
235
|
+
return buf[pos + 1] | (buf[pos] << 8)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def buffer_to_uint16(buf: bytearray, pos: int, endian: int) -> int:
|
|
239
|
+
return _ustr_uint16(buf, pos, endian)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
# Alignment padding is handled with the following formula below
|
|
243
|
+
#
|
|
244
|
+
# For any align value, the correct padding formula is:
|
|
245
|
+
#
|
|
246
|
+
# (align - (pos % align)) % align
|
|
247
|
+
#
|
|
248
|
+
# However, if align is a power of 2 (always the case here), the slow MOD
|
|
249
|
+
# operator can be replaced by a bitwise AND:
|
|
250
|
+
#
|
|
251
|
+
# (align - (pos & (align - 1))) & (align - 1)
|
|
252
|
+
#
|
|
253
|
+
# Which can be simplified to:
|
|
254
|
+
#
|
|
255
|
+
# (-pos) & (align - 1)
|
|
256
|
+
#
|
|
257
|
+
#
|
|
258
|
+
class Unmarshaller:
|
|
259
|
+
"""Unmarshall messages from a stream.
|
|
260
|
+
|
|
261
|
+
When calling with sock and _negotiate_unix_fd False, the unmashaller must
|
|
262
|
+
be called continuously for each new message as it will buffer the data
|
|
263
|
+
until a complete message is available.
|
|
264
|
+
"""
|
|
265
|
+
|
|
266
|
+
__slots__ = (
|
|
267
|
+
"_body_len",
|
|
268
|
+
"_buf",
|
|
269
|
+
"_buf_len",
|
|
270
|
+
"_buf_ustr",
|
|
271
|
+
"_endian",
|
|
272
|
+
"_flag",
|
|
273
|
+
"_header_len",
|
|
274
|
+
"_int16_unpack",
|
|
275
|
+
"_message",
|
|
276
|
+
"_message_type",
|
|
277
|
+
"_msg_len",
|
|
278
|
+
"_negotiate_unix_fd",
|
|
279
|
+
"_pos",
|
|
280
|
+
"_read_complete",
|
|
281
|
+
"_readers",
|
|
282
|
+
"_serial",
|
|
283
|
+
"_sock",
|
|
284
|
+
"_sock_with_fds_reader",
|
|
285
|
+
"_sock_without_fds_reader",
|
|
286
|
+
"_stream",
|
|
287
|
+
"_stream_reader",
|
|
288
|
+
"_uint16_unpack",
|
|
289
|
+
"_uint32_unpack",
|
|
290
|
+
"_unix_fds",
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
_stream_reader: Callable[[int], bytes]
|
|
294
|
+
|
|
295
|
+
def __init__(
|
|
296
|
+
self,
|
|
297
|
+
stream: io.BufferedRWPair | None = None,
|
|
298
|
+
sock: socket.socket | None = None,
|
|
299
|
+
negotiate_unix_fd: bool = True,
|
|
300
|
+
) -> None:
|
|
301
|
+
self._unix_fds: list[int] = []
|
|
302
|
+
self._buf: bytearray = bytearray.__new__(bytearray) # Actual buffer
|
|
303
|
+
self._buf_ustr = self._buf # Used to avoid type checks
|
|
304
|
+
self._buf_len = 0
|
|
305
|
+
self._stream = stream
|
|
306
|
+
self._sock = sock
|
|
307
|
+
self._message: Message | None = None
|
|
308
|
+
self._readers: dict[str, READER_TYPE] = {}
|
|
309
|
+
self._pos = 0
|
|
310
|
+
self._body_len = 0
|
|
311
|
+
self._serial = 0
|
|
312
|
+
self._header_len = 0
|
|
313
|
+
self._message_type = 0
|
|
314
|
+
self._flag = 0
|
|
315
|
+
self._msg_len = 0
|
|
316
|
+
self._uint32_unpack: Callable[[bytearray, int], tuple[int]] | None = None
|
|
317
|
+
self._int16_unpack: Callable[[bytearray, int], tuple[int]] | None = None
|
|
318
|
+
self._uint16_unpack: Callable[[bytearray, int], tuple[int]] | None = None
|
|
319
|
+
self._negotiate_unix_fd = negotiate_unix_fd
|
|
320
|
+
self._read_complete = False
|
|
321
|
+
if stream:
|
|
322
|
+
if isinstance(stream, io.BufferedRWPair) and hasattr(stream, "reader"):
|
|
323
|
+
self._stream_reader = stream.reader.read
|
|
324
|
+
else:
|
|
325
|
+
self._stream_reader = stream.read
|
|
326
|
+
elif self._negotiate_unix_fd:
|
|
327
|
+
if TYPE_CHECKING:
|
|
328
|
+
assert self._sock is not None
|
|
329
|
+
self._sock_with_fds_reader = self._sock.recvmsg
|
|
330
|
+
else:
|
|
331
|
+
if TYPE_CHECKING:
|
|
332
|
+
assert self._sock is not None
|
|
333
|
+
self._sock_without_fds_reader = self._sock.recv
|
|
334
|
+
self._endian = 0
|
|
335
|
+
|
|
336
|
+
def _next_message(self) -> None:
|
|
337
|
+
"""Reset the unmarshaller to its initial state.
|
|
338
|
+
|
|
339
|
+
Call this before processing a new message.
|
|
340
|
+
"""
|
|
341
|
+
if self._unix_fds:
|
|
342
|
+
self._unix_fds = []
|
|
343
|
+
to_clear = HEADER_SIGNATURE_SIZE + self._msg_len
|
|
344
|
+
if self._buf_len == to_clear:
|
|
345
|
+
self._buf = bytearray.__new__(bytearray)
|
|
346
|
+
self._buf_len = 0
|
|
347
|
+
else:
|
|
348
|
+
del self._buf[:to_clear]
|
|
349
|
+
self._buf_len -= to_clear
|
|
350
|
+
self._buf_ustr = self._buf
|
|
351
|
+
self._msg_len = 0 # used to check if we have ready the header
|
|
352
|
+
self._read_complete = False # used to check if we have ready the message
|
|
353
|
+
# No need to reset the unpack functions, they are set in _read_header
|
|
354
|
+
# every time a new message is processed.
|
|
355
|
+
|
|
356
|
+
@property
|
|
357
|
+
def message(self) -> Message | None:
|
|
358
|
+
"""Return the message that has been unmarshalled."""
|
|
359
|
+
if self._read_complete:
|
|
360
|
+
return self._message
|
|
361
|
+
return None
|
|
362
|
+
|
|
363
|
+
def _has_another_message_in_buffer(self) -> bool:
|
|
364
|
+
"""Check if there is another message in the buffer."""
|
|
365
|
+
return self._buf_len > HEADER_SIGNATURE_SIZE + self._msg_len
|
|
366
|
+
|
|
367
|
+
def _read_sock_with_fds(self, pos: _int, missing_bytes: _int) -> None:
|
|
368
|
+
"""reads from the socket, storing any fds sent and handling errors
|
|
369
|
+
from the read itself.
|
|
370
|
+
|
|
371
|
+
This function is greedy and will read as much data as possible
|
|
372
|
+
from the underlying socket.
|
|
373
|
+
"""
|
|
374
|
+
# This will raise BlockingIOError if there is no data to read
|
|
375
|
+
# which we store in the MARSHALL_STREAM_END_ERROR object
|
|
376
|
+
try:
|
|
377
|
+
recv = self._sock_with_fds_reader(missing_bytes, UNIX_FDS_CMSG_LENGTH)
|
|
378
|
+
except OSError as e:
|
|
379
|
+
errno = e.errno
|
|
380
|
+
if errno == EAGAIN or errno == EWOULDBLOCK:
|
|
381
|
+
raise MARSHALL_STREAM_END_ERROR
|
|
382
|
+
raise
|
|
383
|
+
msg = recv[0]
|
|
384
|
+
ancdata = recv[1]
|
|
385
|
+
if ancdata:
|
|
386
|
+
for level, type_, data in ancdata:
|
|
387
|
+
if not (level == SOL_SOCKET and type_ == SCM_RIGHTS):
|
|
388
|
+
continue
|
|
389
|
+
self._unix_fds.extend(
|
|
390
|
+
ARRAY("i", data[: len(data) - (len(data) % MAX_UNIX_FDS_SIZE)])
|
|
391
|
+
)
|
|
392
|
+
if not msg:
|
|
393
|
+
raise EOFError
|
|
394
|
+
self._buf += msg
|
|
395
|
+
self._buf_len = len(self._buf)
|
|
396
|
+
if self._buf_len < pos:
|
|
397
|
+
raise MARSHALL_STREAM_END_ERROR
|
|
398
|
+
|
|
399
|
+
def _read_sock_without_fds(self, pos: _int) -> None:
|
|
400
|
+
"""reads from the socket and handling errors from the read itself.
|
|
401
|
+
|
|
402
|
+
This function is greedy and will read as much data as possible
|
|
403
|
+
from the underlying socket.
|
|
404
|
+
"""
|
|
405
|
+
# This will raise BlockingIOError if there is no data to read
|
|
406
|
+
# which we store in the MARSHALL_STREAM_END_ERROR object
|
|
407
|
+
while True:
|
|
408
|
+
try:
|
|
409
|
+
data = self._sock_without_fds_reader(DEFAULT_BUFFER_SIZE)
|
|
410
|
+
except OSError as e:
|
|
411
|
+
errno = e.errno
|
|
412
|
+
if errno == EAGAIN or errno == EWOULDBLOCK:
|
|
413
|
+
raise MARSHALL_STREAM_END_ERROR
|
|
414
|
+
raise
|
|
415
|
+
if not data:
|
|
416
|
+
raise EOFError
|
|
417
|
+
self._buf += data
|
|
418
|
+
self._buf_len = len(self._buf)
|
|
419
|
+
if self._buf_len >= pos:
|
|
420
|
+
return
|
|
421
|
+
|
|
422
|
+
def _read_stream(self, pos: _int, missing_bytes: _int) -> None:
|
|
423
|
+
"""Read from the stream."""
|
|
424
|
+
data = self._stream_reader(missing_bytes)
|
|
425
|
+
if data is None:
|
|
426
|
+
raise MARSHALL_STREAM_END_ERROR
|
|
427
|
+
if not data:
|
|
428
|
+
raise EOFError
|
|
429
|
+
self._buf += data
|
|
430
|
+
self._buf_len = len(self._buf)
|
|
431
|
+
if self._buf_len < pos:
|
|
432
|
+
raise MARSHALL_STREAM_END_ERROR
|
|
433
|
+
|
|
434
|
+
def _read_to_pos(self, pos: _int) -> None:
|
|
435
|
+
"""
|
|
436
|
+
Read from underlying socket into buffer.
|
|
437
|
+
|
|
438
|
+
Raises BlockingIOError if there is not enough data to be read.
|
|
439
|
+
|
|
440
|
+
:arg pos:
|
|
441
|
+
The pos to read to. If not enough bytes are available in the
|
|
442
|
+
buffer, read more from it.
|
|
443
|
+
|
|
444
|
+
:returns:
|
|
445
|
+
None
|
|
446
|
+
"""
|
|
447
|
+
missing_bytes = pos - self._buf_len
|
|
448
|
+
if missing_bytes <= 0:
|
|
449
|
+
return
|
|
450
|
+
if self._sock is None:
|
|
451
|
+
self._read_stream(pos, missing_bytes)
|
|
452
|
+
elif self._negotiate_unix_fd:
|
|
453
|
+
self._read_sock_with_fds(pos, missing_bytes)
|
|
454
|
+
else:
|
|
455
|
+
self._read_sock_without_fds(pos)
|
|
456
|
+
self._buf_ustr = self._buf
|
|
457
|
+
|
|
458
|
+
def read_uint32_unpack(self, type_: _SignatureType) -> int:
|
|
459
|
+
return self._read_uint32_unpack()
|
|
460
|
+
|
|
461
|
+
def _read_uint32_unpack(self) -> int:
|
|
462
|
+
self._pos += UINT32_SIZE + (-self._pos & (UINT32_SIZE - 1)) # align
|
|
463
|
+
if cython.compiled:
|
|
464
|
+
if self._buf_len < self._pos:
|
|
465
|
+
raise IndexError("Not enough data to read uint32")
|
|
466
|
+
return _ustr_uint32(self._buf_ustr, self._pos - UINT32_SIZE, self._endian)
|
|
467
|
+
return self._uint32_unpack(self._buf, self._pos - UINT32_SIZE)[0]
|
|
468
|
+
|
|
469
|
+
def read_uint16_unpack(self, type_: _SignatureType) -> int:
|
|
470
|
+
return self._read_uint16_unpack()
|
|
471
|
+
|
|
472
|
+
def _read_uint16_unpack(self) -> int:
|
|
473
|
+
self._pos += UINT16_SIZE + (-self._pos & (UINT16_SIZE - 1)) # align
|
|
474
|
+
if cython.compiled:
|
|
475
|
+
if self._buf_len < self._pos:
|
|
476
|
+
raise IndexError("Not enough data to read uint16")
|
|
477
|
+
return _ustr_uint16(self._buf_ustr, self._pos - UINT16_SIZE, self._endian)
|
|
478
|
+
return self._uint16_unpack(self._buf, self._pos - UINT16_SIZE)[0]
|
|
479
|
+
|
|
480
|
+
def read_int16_unpack(self, type_: _SignatureType) -> int:
|
|
481
|
+
return self._read_int16_unpack()
|
|
482
|
+
|
|
483
|
+
def _read_int16_unpack(self) -> int:
|
|
484
|
+
self._pos += INT16_SIZE + (-self._pos & (INT16_SIZE - 1)) # align
|
|
485
|
+
if cython.compiled:
|
|
486
|
+
if self._buf_len < self._pos:
|
|
487
|
+
raise IndexError("Not enough data to read int16")
|
|
488
|
+
return _ustr_int16(self._buf_ustr, self._pos - INT16_SIZE, self._endian)
|
|
489
|
+
return self._int16_unpack(self._buf, self._pos - INT16_SIZE)[0]
|
|
490
|
+
|
|
491
|
+
def read_boolean(self, type_: _SignatureType) -> bool:
|
|
492
|
+
return self._read_boolean()
|
|
493
|
+
|
|
494
|
+
def _read_boolean(self) -> bool:
|
|
495
|
+
return bool(self._read_uint32_unpack())
|
|
496
|
+
|
|
497
|
+
def read_string_unpack(self, type_: _SignatureType) -> str:
|
|
498
|
+
return self._read_string_unpack()
|
|
499
|
+
|
|
500
|
+
def _read_string_unpack(self) -> str:
|
|
501
|
+
"""Read a string using unpack."""
|
|
502
|
+
self._pos += UINT32_SIZE + (-self._pos & (UINT32_SIZE - 1)) # align
|
|
503
|
+
str_start = self._pos
|
|
504
|
+
# read terminating '\0' byte as well (str_length + 1)
|
|
505
|
+
if cython.compiled:
|
|
506
|
+
if self._buf_len < self._pos:
|
|
507
|
+
raise IndexError("Not enough data to read uint32")
|
|
508
|
+
self._pos += (
|
|
509
|
+
_ustr_uint32(self._buf_ustr, str_start - UINT32_SIZE, self._endian) + 1
|
|
510
|
+
)
|
|
511
|
+
if self._buf_len < self._pos:
|
|
512
|
+
raise IndexError("Not enough data to read string")
|
|
513
|
+
else:
|
|
514
|
+
self._pos += self._uint32_unpack(self._buf, str_start - UINT32_SIZE)[0] + 1
|
|
515
|
+
return self._buf_ustr[str_start : self._pos - 1].decode()
|
|
516
|
+
|
|
517
|
+
def read_signature(self, type_: _SignatureType) -> str:
|
|
518
|
+
return self._read_signature()
|
|
519
|
+
|
|
520
|
+
def _read_signature(self) -> str:
|
|
521
|
+
if cython.compiled:
|
|
522
|
+
if self._buf_len < self._pos:
|
|
523
|
+
raise IndexError("Not enough data to read signature")
|
|
524
|
+
signature_len = self._buf_ustr[self._pos] # byte
|
|
525
|
+
o = self._pos + 1
|
|
526
|
+
# read terminating '\0' byte as well (str_length + 1)
|
|
527
|
+
self._pos = o + signature_len + 1
|
|
528
|
+
if cython.compiled:
|
|
529
|
+
if self._buf_len < self._pos:
|
|
530
|
+
raise IndexError("Not enough data to read signature")
|
|
531
|
+
return self._buf_ustr[o : o + signature_len].decode()
|
|
532
|
+
|
|
533
|
+
def read_variant(self, type_: _SignatureType) -> Variant:
|
|
534
|
+
return self._read_variant()
|
|
535
|
+
|
|
536
|
+
def _read_variant(self) -> Variant:
|
|
537
|
+
signature = self._read_signature()
|
|
538
|
+
token_as_int = ord(signature[0])
|
|
539
|
+
# verify in Variant is only useful on construction not unmarshalling
|
|
540
|
+
if len(signature) == 1:
|
|
541
|
+
if token_as_int == TOKEN_N_AS_INT:
|
|
542
|
+
return Variant._factory(SIGNATURE_TREE_N, self._read_int16_unpack())
|
|
543
|
+
if token_as_int == TOKEN_S_AS_INT:
|
|
544
|
+
return Variant._factory(SIGNATURE_TREE_S, self._read_string_unpack())
|
|
545
|
+
if token_as_int == TOKEN_B_AS_INT:
|
|
546
|
+
return VARIANT_BOOL_TRUE if self._read_boolean() else VARIANT_BOOL_FALSE
|
|
547
|
+
if token_as_int == TOKEN_O_AS_INT:
|
|
548
|
+
return Variant._factory(SIGNATURE_TREE_O, self._read_string_unpack())
|
|
549
|
+
if token_as_int == TOKEN_U_AS_INT:
|
|
550
|
+
return Variant._factory(SIGNATURE_TREE_U, self._read_uint32_unpack())
|
|
551
|
+
if token_as_int == TOKEN_Y_AS_INT:
|
|
552
|
+
if cython.compiled:
|
|
553
|
+
if self._buf_len < self._pos:
|
|
554
|
+
raise IndexError("Not enough data to read byte")
|
|
555
|
+
self._pos += 1
|
|
556
|
+
return Variant._factory(SIGNATURE_TREE_Y, self._buf_ustr[self._pos - 1])
|
|
557
|
+
elif token_as_int == TOKEN_A_AS_INT:
|
|
558
|
+
if signature == "ay":
|
|
559
|
+
return Variant._factory(
|
|
560
|
+
SIGNATURE_TREE_AY, self.read_array(SIGNATURE_TREE_AY_TYPES_0)
|
|
561
|
+
)
|
|
562
|
+
if signature == "a{qv}":
|
|
563
|
+
return Variant._factory(
|
|
564
|
+
SIGNATURE_TREE_A_QV, self.read_array(SIGNATURE_TREE_A_QV_TYPES_0)
|
|
565
|
+
)
|
|
566
|
+
if signature == "as":
|
|
567
|
+
return Variant._factory(
|
|
568
|
+
SIGNATURE_TREE_AS, self.read_array(SIGNATURE_TREE_AS_TYPES_0)
|
|
569
|
+
)
|
|
570
|
+
if signature == "a{sv}":
|
|
571
|
+
return Variant._factory(
|
|
572
|
+
SIGNATURE_TREE_A_SV, self.read_array(SIGNATURE_TREE_A_SV_TYPES_0)
|
|
573
|
+
)
|
|
574
|
+
if signature == "ao":
|
|
575
|
+
return Variant._factory(
|
|
576
|
+
SIGNATURE_TREE_AO, self.read_array(SIGNATURE_TREE_AO_TYPES_0)
|
|
577
|
+
)
|
|
578
|
+
tree = get_signature_tree(signature)
|
|
579
|
+
signature_type = tree.root_type
|
|
580
|
+
return Variant._factory(
|
|
581
|
+
tree, self._readers[signature_type.token](self, signature_type)
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
def read_struct(self, type_: _SignatureType) -> list[Any]:
|
|
585
|
+
self._pos += -self._pos & 7 # align 8
|
|
586
|
+
readers = self._readers
|
|
587
|
+
return [
|
|
588
|
+
readers[child_type.token](self, child_type) for child_type in type_.children
|
|
589
|
+
]
|
|
590
|
+
|
|
591
|
+
def read_dict_entry(self, type_: _SignatureType) -> tuple[Any, Any]:
|
|
592
|
+
self._pos += -self._pos & 7 # align 8
|
|
593
|
+
return self._readers[type_.children[0].token](
|
|
594
|
+
self, type_.children[0]
|
|
595
|
+
), self._readers[type_.children[1].token](self, type_.children[1])
|
|
596
|
+
|
|
597
|
+
def read_array(self, type_: _SignatureType) -> Iterable[Any]:
|
|
598
|
+
self._pos += -self._pos & 3 # align 4 for the array
|
|
599
|
+
self._pos += (
|
|
600
|
+
-self._pos & (UINT32_SIZE - 1)
|
|
601
|
+
) + UINT32_SIZE # align for the uint32
|
|
602
|
+
if cython.compiled:
|
|
603
|
+
if self._buf_len < self._pos:
|
|
604
|
+
raise IndexError("Not enough data to read uint32")
|
|
605
|
+
array_length = _ustr_uint32(
|
|
606
|
+
self._buf_ustr, self._pos - UINT32_SIZE, self._endian
|
|
607
|
+
)
|
|
608
|
+
else:
|
|
609
|
+
array_length = self._uint32_unpack(self._buf, self._pos - UINT32_SIZE)[0]
|
|
610
|
+
child_type = type_._child_0
|
|
611
|
+
token_as_int = child_type.token_as_int
|
|
612
|
+
|
|
613
|
+
if token_as_int in {
|
|
614
|
+
TOKEN_X_AS_INT,
|
|
615
|
+
TOKEN_T_AS_INT,
|
|
616
|
+
TOKEN_D_AS_INT,
|
|
617
|
+
TOKEN_LEFT_CURLY_AS_INT,
|
|
618
|
+
TOKEN_LEFT_PAREN_AS_INT,
|
|
619
|
+
}:
|
|
620
|
+
# the first alignment is not included in the array size
|
|
621
|
+
self._pos += -self._pos & 7 # align 8
|
|
622
|
+
|
|
623
|
+
if token_as_int == TOKEN_Y_AS_INT:
|
|
624
|
+
self._pos += array_length
|
|
625
|
+
if cython.compiled:
|
|
626
|
+
if self._buf_len < self._pos:
|
|
627
|
+
raise IndexError("Not enough data to read byte")
|
|
628
|
+
return self._buf_ustr[self._pos - array_length : self._pos]
|
|
629
|
+
|
|
630
|
+
if token_as_int == TOKEN_LEFT_CURLY_AS_INT:
|
|
631
|
+
result_dict: dict[Any, Any] = {}
|
|
632
|
+
key: str | int
|
|
633
|
+
beginning_pos = self._pos
|
|
634
|
+
child_0 = child_type._child_0
|
|
635
|
+
child_1 = child_type._child_1
|
|
636
|
+
child_0_token_as_int = child_0.token_as_int
|
|
637
|
+
child_1_token_as_int = child_1.token_as_int
|
|
638
|
+
# Strings with variant values are the most common case
|
|
639
|
+
# so we optimize for that by inlining the string reading
|
|
640
|
+
# and the variant reading here
|
|
641
|
+
if (
|
|
642
|
+
child_0_token_as_int in {TOKEN_O_AS_INT, TOKEN_S_AS_INT}
|
|
643
|
+
and child_1_token_as_int == TOKEN_V_AS_INT
|
|
644
|
+
):
|
|
645
|
+
while self._pos - beginning_pos < array_length:
|
|
646
|
+
self._pos += -self._pos & 7 # align 8
|
|
647
|
+
key = self._read_string_unpack()
|
|
648
|
+
result_dict[key] = self._read_variant()
|
|
649
|
+
elif (
|
|
650
|
+
child_0_token_as_int == TOKEN_Q_AS_INT
|
|
651
|
+
and child_1_token_as_int == TOKEN_V_AS_INT
|
|
652
|
+
):
|
|
653
|
+
while self._pos - beginning_pos < array_length:
|
|
654
|
+
self._pos += -self._pos & 7 # align 8
|
|
655
|
+
key = self._read_uint16_unpack()
|
|
656
|
+
result_dict[key] = self._read_variant()
|
|
657
|
+
elif (
|
|
658
|
+
child_0_token_as_int in {TOKEN_O_AS_INT, TOKEN_S_AS_INT}
|
|
659
|
+
and child_1_token_as_int == TOKEN_A_AS_INT
|
|
660
|
+
):
|
|
661
|
+
while self._pos - beginning_pos < array_length:
|
|
662
|
+
self._pos += -self._pos & 7 # align 8
|
|
663
|
+
key = self._read_string_unpack()
|
|
664
|
+
result_dict[key] = self.read_array(child_1)
|
|
665
|
+
else:
|
|
666
|
+
reader_1 = self._readers[child_1.token]
|
|
667
|
+
reader_0 = self._readers[child_0.token]
|
|
668
|
+
while self._pos - beginning_pos < array_length:
|
|
669
|
+
self._pos += -self._pos & 7 # align 8
|
|
670
|
+
key = reader_0(self, child_0)
|
|
671
|
+
result_dict[key] = reader_1(self, child_1)
|
|
672
|
+
|
|
673
|
+
return result_dict
|
|
674
|
+
|
|
675
|
+
if array_length == 0:
|
|
676
|
+
return []
|
|
677
|
+
|
|
678
|
+
result_list = []
|
|
679
|
+
beginning_pos = self._pos
|
|
680
|
+
if token_as_int == TOKEN_O_AS_INT or token_as_int == TOKEN_S_AS_INT:
|
|
681
|
+
while self._pos - beginning_pos < array_length:
|
|
682
|
+
result_list.append(self._read_string_unpack())
|
|
683
|
+
return result_list
|
|
684
|
+
reader = self._readers[child_type.token]
|
|
685
|
+
while self._pos - beginning_pos < array_length:
|
|
686
|
+
result_list.append(reader(self, child_type))
|
|
687
|
+
return result_list
|
|
688
|
+
|
|
689
|
+
def _header_fields(self, header_length: _int) -> list[Any]:
|
|
690
|
+
"""Header fields are always a(yv)."""
|
|
691
|
+
beginning_pos = self._pos
|
|
692
|
+
headers = _EMPTY_HEADERS.copy()
|
|
693
|
+
if cython.compiled:
|
|
694
|
+
if self._buf_len < self._pos + header_length:
|
|
695
|
+
raise IndexError("Not enough data to read header")
|
|
696
|
+
while self._pos - beginning_pos < header_length:
|
|
697
|
+
# Now read the y (byte) of struct (yv)
|
|
698
|
+
self._pos += (-self._pos & 7) + 1 # align 8 + 1 for 'y' byte
|
|
699
|
+
field_0 = self._buf_ustr[self._pos - 1]
|
|
700
|
+
|
|
701
|
+
# Now read the v (variant) of struct (yv)
|
|
702
|
+
# first we read the signature
|
|
703
|
+
signature_len = self._buf_ustr[self._pos] # byte
|
|
704
|
+
o = self._pos + 1
|
|
705
|
+
if cython.compiled:
|
|
706
|
+
if self._buf_len < o + signature_len:
|
|
707
|
+
raise IndexError("Not enough data to read signature")
|
|
708
|
+
self._pos += signature_len + 2 # one for the byte, one for the '\0'
|
|
709
|
+
if field_0 == HEADER_UNIX_FDS_IDX: # defined by self._unix_fds
|
|
710
|
+
continue
|
|
711
|
+
token_as_int = self._buf_ustr[o]
|
|
712
|
+
# Now that we have the token we can read the variant value
|
|
713
|
+
# Strings and signatures are the most common types
|
|
714
|
+
# so we inline them for performance
|
|
715
|
+
if token_as_int == TOKEN_O_AS_INT or token_as_int == TOKEN_S_AS_INT:
|
|
716
|
+
headers[field_0] = self._read_string_unpack()
|
|
717
|
+
elif token_as_int == TOKEN_G_AS_INT:
|
|
718
|
+
headers[field_0] = self._read_signature()
|
|
719
|
+
else:
|
|
720
|
+
token = self._buf_ustr[o : o + signature_len].decode()
|
|
721
|
+
# There shouldn't be any other types in the header
|
|
722
|
+
# but just in case, we'll read it using the slow path
|
|
723
|
+
headers[field_0] = self._readers[token](
|
|
724
|
+
self, get_signature_tree(token).root_type
|
|
725
|
+
)
|
|
726
|
+
return headers
|
|
727
|
+
|
|
728
|
+
def _read_header(self) -> None:
|
|
729
|
+
"""Read the header of the message."""
|
|
730
|
+
# Signature is of the header is
|
|
731
|
+
# BYTE, BYTE, BYTE, BYTE, UINT32, UINT32, ARRAY of STRUCT of (BYTE,VARIANT)
|
|
732
|
+
self._read_to_pos(HEADER_SIGNATURE_SIZE)
|
|
733
|
+
endian = self._buf_ustr[0]
|
|
734
|
+
self._message_type = self._buf_ustr[1]
|
|
735
|
+
self._flag = self._buf_ustr[2]
|
|
736
|
+
protocol_version = self._buf_ustr[3]
|
|
737
|
+
|
|
738
|
+
if protocol_version != PROTOCOL_VERSION:
|
|
739
|
+
raise InvalidMessageError(
|
|
740
|
+
f"got unknown protocol version: {protocol_version}"
|
|
741
|
+
)
|
|
742
|
+
|
|
743
|
+
if endian != LITTLE_ENDIAN and endian != BIG_ENDIAN:
|
|
744
|
+
raise InvalidMessageError(
|
|
745
|
+
f"Expecting endianness as the first byte, got {endian} from {self._buf}"
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
if cython.compiled:
|
|
749
|
+
self._body_len = _ustr_uint32(self._buf_ustr, 4, endian)
|
|
750
|
+
self._serial = _ustr_uint32(self._buf_ustr, 8, endian)
|
|
751
|
+
self._header_len = _ustr_uint32(self._buf_ustr, 12, endian)
|
|
752
|
+
elif endian == LITTLE_ENDIAN:
|
|
753
|
+
(
|
|
754
|
+
self._body_len,
|
|
755
|
+
self._serial,
|
|
756
|
+
self._header_len,
|
|
757
|
+
) = UNPACK_HEADER_LITTLE_ENDIAN(self._buf, 4)
|
|
758
|
+
self._uint32_unpack = UINT32_UNPACK_LITTLE_ENDIAN
|
|
759
|
+
self._int16_unpack = INT16_UNPACK_LITTLE_ENDIAN
|
|
760
|
+
self._uint16_unpack = UINT16_UNPACK_LITTLE_ENDIAN
|
|
761
|
+
else: # BIG_ENDIAN
|
|
762
|
+
self._body_len, self._serial, self._header_len = UNPACK_HEADER_BIG_ENDIAN(
|
|
763
|
+
self._buf, 4
|
|
764
|
+
)
|
|
765
|
+
self._uint32_unpack = UINT32_UNPACK_BIG_ENDIAN
|
|
766
|
+
self._int16_unpack = INT16_UNPACK_BIG_ENDIAN
|
|
767
|
+
self._uint16_unpack = UINT16_UNPACK_BIG_ENDIAN
|
|
768
|
+
|
|
769
|
+
# align 8
|
|
770
|
+
self._msg_len = self._header_len + (-self._header_len & 7) + self._body_len
|
|
771
|
+
if self._endian != endian:
|
|
772
|
+
self._readers = self._readers_by_type[endian]
|
|
773
|
+
self._endian = endian
|
|
774
|
+
|
|
775
|
+
def _read_body(self) -> None:
|
|
776
|
+
"""Read the body of the message."""
|
|
777
|
+
self._read_to_pos(HEADER_SIGNATURE_SIZE + self._msg_len)
|
|
778
|
+
self._pos = HEADER_ARRAY_OF_STRUCT_SIGNATURE_POSITION
|
|
779
|
+
header_fields = self._header_fields(self._header_len)
|
|
780
|
+
self._pos += -self._pos & 7 # align 8
|
|
781
|
+
signature: str = header_fields[HEADER_SIGNATURE_IDX]
|
|
782
|
+
if not self._body_len:
|
|
783
|
+
tree = SIGNATURE_TREE_EMPTY
|
|
784
|
+
body: list[Any] = []
|
|
785
|
+
else:
|
|
786
|
+
token_as_int = ord(signature[0])
|
|
787
|
+
if len(signature) == 1:
|
|
788
|
+
if token_as_int == TOKEN_O_AS_INT:
|
|
789
|
+
tree = SIGNATURE_TREE_O
|
|
790
|
+
body = [self._read_string_unpack()]
|
|
791
|
+
elif token_as_int == TOKEN_S_AS_INT:
|
|
792
|
+
tree = SIGNATURE_TREE_S
|
|
793
|
+
body = [self._read_string_unpack()]
|
|
794
|
+
else:
|
|
795
|
+
tree = get_signature_tree(signature)
|
|
796
|
+
body = [self._readers[t.token](self, t) for t in tree.types]
|
|
797
|
+
elif token_as_int == TOKEN_S_AS_INT and signature == "sa{sv}as":
|
|
798
|
+
tree = SIGNATURE_TREE_SA_SV_AS
|
|
799
|
+
body = [
|
|
800
|
+
self._read_string_unpack(),
|
|
801
|
+
self.read_array(SIGNATURE_TREE_SA_SV_AS_TYPES_1),
|
|
802
|
+
self.read_array(SIGNATURE_TREE_SA_SV_AS_TYPES_2),
|
|
803
|
+
]
|
|
804
|
+
elif token_as_int == TOKEN_O_AS_INT and signature == "oa{sa{sv}}":
|
|
805
|
+
tree = SIGNATURE_TREE_OA_SA_SV
|
|
806
|
+
body = [
|
|
807
|
+
self._read_string_unpack(),
|
|
808
|
+
self.read_array(SIGNATURE_TREE_OA_SA_SV_TYPES_1),
|
|
809
|
+
]
|
|
810
|
+
elif token_as_int == TOKEN_O_AS_INT and signature == "oas":
|
|
811
|
+
tree = SIGNATURE_TREE_OAS
|
|
812
|
+
body = [
|
|
813
|
+
self._read_string_unpack(),
|
|
814
|
+
self.read_array(SIGNATURE_TREE_OAS_TYPES_1),
|
|
815
|
+
]
|
|
816
|
+
elif token_as_int == TOKEN_A_AS_INT and signature == "a{oa{sa{sv}}}":
|
|
817
|
+
tree = SIGNATURE_TREE_A_OA_SA_SV
|
|
818
|
+
body = [self.read_array(SIGNATURE_TREE_A_OA_SA_SV_TYPES_0)]
|
|
819
|
+
else:
|
|
820
|
+
tree = get_signature_tree(signature)
|
|
821
|
+
body = [self._readers[t.token](self, t) for t in tree.types]
|
|
822
|
+
|
|
823
|
+
flags = MESSAGE_FLAG_MAP.get(self._flag)
|
|
824
|
+
if flags is None:
|
|
825
|
+
flags = MESSAGE_FLAG_INTENUM(self._flag)
|
|
826
|
+
message = Message.__new__(Message)
|
|
827
|
+
message._fast_init(
|
|
828
|
+
header_fields[HEADER_DESTINATION_IDX],
|
|
829
|
+
header_fields[HEADER_PATH_IDX],
|
|
830
|
+
header_fields[HEADER_INTERFACE_IDX],
|
|
831
|
+
header_fields[HEADER_MEMBER_IDX],
|
|
832
|
+
MESSAGE_TYPE_MAP[self._message_type],
|
|
833
|
+
flags,
|
|
834
|
+
header_fields[HEADER_ERROR_NAME_IDX],
|
|
835
|
+
header_fields[HEADER_REPLY_SERIAL_IDX] or 0,
|
|
836
|
+
header_fields[HEADER_SENDER_IDX],
|
|
837
|
+
self._unix_fds,
|
|
838
|
+
tree,
|
|
839
|
+
body,
|
|
840
|
+
self._serial,
|
|
841
|
+
# The D-Bus implementation already validates the message,
|
|
842
|
+
# so we don't need to do it again.
|
|
843
|
+
False,
|
|
844
|
+
)
|
|
845
|
+
self._message = message
|
|
846
|
+
self._read_complete = True
|
|
847
|
+
|
|
848
|
+
def unmarshall(self) -> Message | None:
|
|
849
|
+
"""Unmarshall the message.
|
|
850
|
+
|
|
851
|
+
The underlying read function will raise BlockingIOError if the
|
|
852
|
+
if there are not enough bytes in the buffer. This allows unmarshall
|
|
853
|
+
to be resumed when more data comes in over the wire.
|
|
854
|
+
"""
|
|
855
|
+
return self._unmarshall()
|
|
856
|
+
|
|
857
|
+
def _unmarshall(self) -> Message | None:
|
|
858
|
+
"""Unmarshall the message.
|
|
859
|
+
|
|
860
|
+
The underlying read function will raise BlockingIOError if the
|
|
861
|
+
if there are not enough bytes in the buffer. This allows unmarshall
|
|
862
|
+
to be resumed when more data comes in over the wire.
|
|
863
|
+
"""
|
|
864
|
+
if self._read_complete:
|
|
865
|
+
self._next_message()
|
|
866
|
+
try:
|
|
867
|
+
if not self._msg_len:
|
|
868
|
+
self._read_header()
|
|
869
|
+
self._read_body()
|
|
870
|
+
except MARSHALL_STREAM_END_ERROR:
|
|
871
|
+
return None
|
|
872
|
+
return self._message
|
|
873
|
+
|
|
874
|
+
_complex_parsers_unpack: dict[str, Callable[[Unmarshaller, SignatureType], Any]] = {
|
|
875
|
+
"b": read_boolean,
|
|
876
|
+
"o": read_string_unpack,
|
|
877
|
+
"s": read_string_unpack,
|
|
878
|
+
"g": read_signature,
|
|
879
|
+
"a": read_array,
|
|
880
|
+
"(": read_struct,
|
|
881
|
+
"{": read_dict_entry,
|
|
882
|
+
"v": read_variant,
|
|
883
|
+
"h": read_uint32_unpack,
|
|
884
|
+
UINT32_DBUS_TYPE: read_uint32_unpack,
|
|
885
|
+
INT16_DBUS_TYPE: read_int16_unpack,
|
|
886
|
+
UINT16_DBUS_TYPE: read_uint16_unpack,
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
_ctype_by_endian: dict[int, dict[str, READER_TYPE]] = {
|
|
890
|
+
endian: build_simple_parsers(endian) for endian in (LITTLE_ENDIAN, BIG_ENDIAN)
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
_readers_by_type: dict[int, dict[str, READER_TYPE]] = {
|
|
894
|
+
LITTLE_ENDIAN: {
|
|
895
|
+
**_ctype_by_endian[LITTLE_ENDIAN],
|
|
896
|
+
**_complex_parsers_unpack,
|
|
897
|
+
},
|
|
898
|
+
BIG_ENDIAN: {
|
|
899
|
+
**_ctype_by_endian[BIG_ENDIAN],
|
|
900
|
+
**_complex_parsers_unpack,
|
|
901
|
+
},
|
|
902
|
+
}
|