AcraNetwork 1.2.7__tar.gz → 1.2.8__tar.gz
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.
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter7/Golay.py +62 -65
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/Pcap.py +67 -3
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/__version__.py +6 -2
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork.egg-info/PKG-INFO +1 -1
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork.egg-info/SOURCES.txt +0 -1
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork.egg-info/top_level.txt +0 -1
- {acranetwork-1.2.7 → acranetwork-1.2.8}/PKG-INFO +1 -1
- acranetwork-1.2.8/test/test_golay.py +623 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_pcap.py +50 -0
- acranetwork-1.2.7/test/__init__.py +0 -0
- acranetwork-1.2.7/test/test_golay.py +0 -321
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IENA.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter10/Chapter10UDP.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter10/FileParser.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter10/__init__.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/ARINC429.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/Analog.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/CAN.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/ComputerData.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/MILSTD1553.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/PCM.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/TimeDataFormat.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/UART.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/Video.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/__init__.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter7/__init__.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter7/golay_c.c +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/__init__.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEG/ADTS.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEG/H264.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEG/PES.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEG/PMT.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEG/STANAG4609.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEG/__init__.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEGTS.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/McastSocket.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/NPD.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/ParserAligned.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/SamDec008.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/SimpleEthernet.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/__init__.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/iNET.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/iNetX.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/nanotime.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/ptptime.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork.egg-info/dependency_links.txt +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/LICENSE +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/MANIFEST.in +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/README.md +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/adau_to_ch10.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/ch10_recorder.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/ch10_to_pcap.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/pkg_gen.ini +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/tx_iena_udp.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/tx_inetx_udp.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/validate_ch10.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/validate_pcap.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/setup.cfg +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/setup.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_afdx.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_ch10.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_ch7.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_iena.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_inet.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_inetx.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_misc.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_mpegts.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_npd.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_paligned.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_ptptime.py +0 -0
- {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_simpleethernet.py +0 -0
|
@@ -33,30 +33,37 @@ G_P = [0xC75, 0x63B, 0xF68, 0x7B4, 0x3DA, 0xD99, 0x6CD, 0x367, 0xDC6, 0xA97, 0x9
|
|
|
33
33
|
H_P = [0xA4F, 0xF68, 0x7B4, 0x3DA, 0x1ED, 0xAB9, 0xF13, 0xDC6, 0x6E3, 0x93E, 0x49F, 0xC75]
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
class
|
|
37
|
-
_instances = {}
|
|
38
|
-
|
|
39
|
-
def __call__(cls, *args, **kwargs):
|
|
40
|
-
if cls not in cls._instances:
|
|
41
|
-
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
|
|
42
|
-
return cls._instances[cls]
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class Golay(object):
|
|
46
|
-
__metaclass__ = Singleton
|
|
36
|
+
class Golay:
|
|
47
37
|
"""
|
|
48
38
|
Encode and Decode Golay numbers
|
|
49
39
|
"""
|
|
50
40
|
|
|
41
|
+
# Look-up tables are class variables. They will be initialised by the
|
|
42
|
+
# constructor of the first instance of the Golay class to be created.
|
|
43
|
+
# Set them to None here so the constructor can tell that they must be
|
|
44
|
+
# set up.
|
|
45
|
+
EncodeTable = None
|
|
46
|
+
SyndromeTable = None
|
|
47
|
+
CorrectTable = None
|
|
48
|
+
ErrorTable = None
|
|
49
|
+
|
|
51
50
|
def __init__(self):
|
|
52
51
|
if _use_c_extension:
|
|
53
52
|
_golay_native.golay_init_tables()
|
|
54
53
|
else:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
self.ErrorTable = [0] * GOLAY_SIZE
|
|
54
|
+
if Golay.EncodeTable is None:
|
|
55
|
+
self._init_encode_table()
|
|
58
56
|
self._initgolaydecode()
|
|
59
57
|
|
|
58
|
+
|
|
59
|
+
def _init_encode_table(self):
|
|
60
|
+
Golay.EncodeTable = [0] * GOLAY_SIZE
|
|
61
|
+
for x in range(GOLAY_SIZE):
|
|
62
|
+
Golay.EncodeTable[x] = x << 12
|
|
63
|
+
for i in range(12):
|
|
64
|
+
if x >> (11 - i) & 1:
|
|
65
|
+
Golay.EncodeTable[x] ^= G_P[i]
|
|
66
|
+
|
|
60
67
|
def encode(self, raw, as_string=False):
|
|
61
68
|
if not (0 <= raw <= 0xFFF):
|
|
62
69
|
raise ValueError("Only 12-bit unsigned values allowed")
|
|
@@ -67,84 +74,70 @@ class Golay(object):
|
|
|
67
74
|
encoded = self._encode_python(raw)
|
|
68
75
|
|
|
69
76
|
if as_string:
|
|
70
|
-
return
|
|
77
|
+
return encoded.to_bytes(3, "big")
|
|
71
78
|
return encoded
|
|
72
79
|
|
|
73
80
|
def decode(self, encoded):
|
|
74
81
|
if _use_c_extension:
|
|
75
82
|
return _golay_native.golay_decode(encoded)
|
|
76
83
|
else:
|
|
77
|
-
|
|
84
|
+
# encoded is either an integer <= 0xFFFFFF, or is a bytes-like type
|
|
85
|
+
if not isinstance(encoded, int):
|
|
78
86
|
if len(encoded) != 3:
|
|
79
87
|
raise ValueError("3-byte input required")
|
|
80
|
-
|
|
81
|
-
v = w + (b << 16)
|
|
88
|
+
v = int.from_bytes(encoded, "big")
|
|
82
89
|
elif not (0 <= encoded <= 0xFFFFFF):
|
|
83
90
|
raise ValueError("Only 24-bit unsigned values supported")
|
|
84
91
|
else:
|
|
85
92
|
v = encoded
|
|
86
93
|
return self._decode_python(v)
|
|
87
94
|
|
|
88
|
-
@staticmethod
|
|
89
|
-
@lru_cache()
|
|
90
|
-
def _init_Table():
|
|
91
|
-
EncodeTable = [0] * GOLAY_SIZE
|
|
92
|
-
for x in range(GOLAY_SIZE):
|
|
93
|
-
EncodeTable[x] = x << 12
|
|
94
|
-
for i in range(12):
|
|
95
|
-
if x >> (11 - i) & 1:
|
|
96
|
-
EncodeTable[x] ^= G_P[i]
|
|
97
|
-
|
|
98
|
-
return EncodeTable
|
|
99
95
|
|
|
100
|
-
def _encode_python(self, raw
|
|
96
|
+
def _encode_python(self, raw):
|
|
101
97
|
"""
|
|
102
98
|
Encode the value as a 24b code
|
|
103
99
|
|
|
100
|
+
The leading '_' indicates this is a private method; do not call this
|
|
101
|
+
directly, call encode() instead.
|
|
102
|
+
|
|
104
103
|
:type raw: int
|
|
105
|
-
:
|
|
104
|
+
:param raw: value to be encoded that is already validated to be 0..FFF
|
|
105
|
+
:return: encoded value as a 24-bit integer
|
|
106
106
|
"""
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
# self.encode() has already checked that 0 <= raw <= 0xFFF so do not
|
|
108
|
+
# check again
|
|
109
|
+
# Also, there is no to_string argument because that is handled by
|
|
110
|
+
# encode()
|
|
109
111
|
|
|
110
|
-
EncodeTable
|
|
111
|
-
encoded = EncodeTable[raw & 0xFFF]
|
|
112
|
-
if as_string:
|
|
113
|
-
return struct.pack(">BH", encoded >> 16, encoded & 0xFFFF)
|
|
114
|
-
else:
|
|
115
|
-
return encoded
|
|
112
|
+
return Golay.EncodeTable[raw & 0xFFF]
|
|
116
113
|
|
|
117
|
-
def _decode_python(self,
|
|
114
|
+
def _decode_python(self, v):
|
|
118
115
|
"""
|
|
119
116
|
Decode a 24b number as a golay
|
|
120
117
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
:return:
|
|
124
|
-
"""
|
|
125
|
-
if type(encoded) is bytes:
|
|
126
|
-
if len(encoded) != 3:
|
|
127
|
-
raise Exception("String to decode should be 3 bytes")
|
|
128
|
-
(b, w) = struct.unpack(">BH", encoded)
|
|
129
|
-
v = w + (b << 16)
|
|
130
|
-
elif 0xFFFFF < encoded < 0:
|
|
131
|
-
raise Exception("Only supports 24b unsigned numbers")
|
|
132
|
-
else:
|
|
133
|
-
v = encoded
|
|
118
|
+
The leading '_' indicates this is a private method; do not call this
|
|
119
|
+
directly, call decode() instead.
|
|
134
120
|
|
|
121
|
+
:type v: int
|
|
122
|
+
:param v: integer that has already been validated to be 24bit
|
|
123
|
+
:return: decoded 12-bit value
|
|
124
|
+
"""
|
|
125
|
+
# self.decode() has converted the value to an integer and verified
|
|
126
|
+
# that it is valid. So do not repeat the check.
|
|
127
|
+
|
|
135
128
|
return self._decode2(((v) >> 12) & 0xFFF, (v) & 0xFFF)
|
|
136
129
|
|
|
137
130
|
def _syndrome2(self, v1, v2):
|
|
138
|
-
return
|
|
131
|
+
return Golay.SyndromeTable[v2] ^ (v1)
|
|
139
132
|
|
|
140
133
|
def _syndrome(self, v):
|
|
141
134
|
return self._syndrome2(((v) >> 12) & 0xFFF, (v) & 0xFFF)
|
|
142
135
|
|
|
143
136
|
def _errors2(self, v1, v2):
|
|
144
|
-
return
|
|
137
|
+
return Golay.ErrorTable[self._syndrome2(v1, v2)]
|
|
145
138
|
|
|
146
139
|
def _decode2(self, v1, v2):
|
|
147
|
-
return (v1) ^
|
|
140
|
+
return (v1) ^ Golay.CorrectTable[self._syndrome2(v1, v2)]
|
|
148
141
|
|
|
149
142
|
def _errors(self, v):
|
|
150
143
|
return self._errors2(((v) >> 12) & 0xFFF, (v) & 0xFFF)
|
|
@@ -171,22 +164,26 @@ class Golay(object):
|
|
|
171
164
|
return ret
|
|
172
165
|
|
|
173
166
|
def _initgolaydecode(self):
|
|
167
|
+
Golay.SyndromeTable = [0] * GOLAY_SIZE
|
|
168
|
+
Golay.CorrectTable = [0] * GOLAY_SIZE
|
|
169
|
+
Golay.ErrorTable = [0] * GOLAY_SIZE
|
|
170
|
+
|
|
174
171
|
for x in range(GOLAY_SIZE):
|
|
175
|
-
|
|
172
|
+
Golay.SyndromeTable[x] = 0
|
|
176
173
|
for i in range(12):
|
|
177
174
|
if (x >> (11 - i)) & 1:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
175
|
+
Golay.SyndromeTable[x] ^= H_P[i]
|
|
176
|
+
Golay.ErrorTable[x] = 4
|
|
177
|
+
Golay.CorrectTable[x] = 0xFFF
|
|
181
178
|
|
|
182
|
-
|
|
183
|
-
|
|
179
|
+
Golay.ErrorTable[0] = 0
|
|
180
|
+
Golay.CorrectTable[0] = 0
|
|
184
181
|
for i in range(24):
|
|
185
182
|
for j in range(24):
|
|
186
183
|
for k in range(24):
|
|
187
184
|
error = (1 << i) | (1 << j) | (1 << k)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
185
|
+
syndrome = self._syndrome(error)
|
|
186
|
+
Golay.CorrectTable[syndrome] = (error >> 12) & 0xFFF
|
|
187
|
+
Golay.ErrorTable[syndrome] = Golay._onesincode(error, 24)
|
|
191
188
|
|
|
192
189
|
return True
|
|
@@ -31,12 +31,18 @@ class PcapRecord(object):
|
|
|
31
31
|
:type _packet: str
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
|
-
def __init__(self):
|
|
34
|
+
def __init__(self, now=False):
|
|
35
|
+
"""
|
|
36
|
+
:param now: if True, record time is set to the current time.
|
|
37
|
+
:type now: bool
|
|
38
|
+
"""
|
|
35
39
|
self.sec: int = 0 #: Second timestamp of the record. Epoch time
|
|
36
40
|
self.usec: int = 0 #: Microsecond timestamp of the record
|
|
37
41
|
self.incl_len: int = 0 #: The number of bytes captured and saved in the file
|
|
38
|
-
self.orig_len: int = 0 #: The number of
|
|
42
|
+
self.orig_len: int = 0 #: The number of bytes as appeared on the network when captured
|
|
39
43
|
self._payload: bytes = bytes()
|
|
44
|
+
if now:
|
|
45
|
+
self.set_current_time()
|
|
40
46
|
|
|
41
47
|
# Use a property on packet so that the length is triggered on it changing
|
|
42
48
|
@property
|
|
@@ -140,8 +146,47 @@ class Pcap(object):
|
|
|
140
146
|
|
|
141
147
|
So after opening the file, iterate through the object to read the records
|
|
142
148
|
|
|
149
|
+
A PCAP file can be opened for reading or writing by specifying mode "r"
|
|
150
|
+
or "w", or for append by specifying "a".
|
|
151
|
+
|
|
152
|
+
When a PCAP file is open for writing or appending, PcapRecord objects can
|
|
153
|
+
be written to it.
|
|
154
|
+
|
|
155
|
+
# Write 10 UDP records to a file
|
|
156
|
+
# For simplicity use the same MAC, IP and UDP headers in all records
|
|
157
|
+
>>> headers = (bytes((0x77,0x88,0x99,0xAA,0xBB,0xCC,0x66,0x55,0x44,0x33,0x22,0x11,
|
|
158
|
+
... 0x08,0x00))
|
|
159
|
+
... +bytes((0x45,0x00,0x00,0x36,0x77,0x77,0x40,0x00,0xff,0x11,0x8a,0xa4,
|
|
160
|
+
... 0x12,0x34,0x56,0x78,0x99,0x88,0x77,0x66))
|
|
161
|
+
... +bytes((0x12,0x34,0x56,0x78,0x00,0x22,0x00,0x00))
|
|
162
|
+
... )
|
|
163
|
+
>>> with Pcap("_dummy.pcap", mode='w') as p:
|
|
164
|
+
... r = PcapRecord()
|
|
165
|
+
... for i in range(10):
|
|
166
|
+
... start_ch = ord('A') + i
|
|
167
|
+
... r.payload = headers + bytes((x for x in range(start_ch,start_ch+26)))
|
|
168
|
+
... p.write(r)
|
|
169
|
+
|
|
170
|
+
When a PCAP file is open for reading, iterate through the records.
|
|
171
|
+
>>> with Pcap("_dummy.pcap", mode='r') as p2:
|
|
172
|
+
... print(f"{p2.filename} contains {p2.filesize} bytes and is open with mode '{p2.mode}'")
|
|
173
|
+
... print(f"Network type ID {p2.network}{' (Ethernet)' if p2.network==1 else ''}")
|
|
174
|
+
... for ix, record in enumerate(p2):
|
|
175
|
+
... print(f"{ix} {record.orig_len} bytes: {record.payload}")
|
|
176
|
+
...
|
|
177
|
+
_dummy.pcap contains 864 bytes and is open with mode 'r'
|
|
178
|
+
Network type ID 1 (Ethernet)
|
|
179
|
+
0 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
|
180
|
+
1 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00BCDEFGHIJKLMNOPQRSTUVWXYZ['
|
|
181
|
+
2 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00CDEFGHIJKLMNOPQRSTUVWXYZ[\\'
|
|
182
|
+
3 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00DEFGHIJKLMNOPQRSTUVWXYZ[\\]'
|
|
183
|
+
4 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00EFGHIJKLMNOPQRSTUVWXYZ[\\]^'
|
|
184
|
+
5 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00FGHIJKLMNOPQRSTUVWXYZ[\\]^_'
|
|
185
|
+
6 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00GHIJKLMNOPQRSTUVWXYZ[\\]^_`'
|
|
186
|
+
7 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00HIJKLMNOPQRSTUVWXYZ[\\]^_`a'
|
|
187
|
+
8 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00IJKLMNOPQRSTUVWXYZ[\\]^_`ab'
|
|
188
|
+
9 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00JKLMNOPQRSTUVWXYZ[\\]^_`abc'
|
|
143
189
|
|
|
144
|
-
Open a PCAP file for reading. Iterate through the records.
|
|
145
190
|
|
|
146
191
|
The pcap can also be treated a list to select the relevant object.
|
|
147
192
|
|
|
@@ -185,11 +230,21 @@ class Pcap(object):
|
|
|
185
230
|
self.network: int = 1 #: Link-layer header type. http://www.tcpdump.org/linktypes.html
|
|
186
231
|
self.filesize = 0
|
|
187
232
|
|
|
233
|
+
# rec_no is convenient if the file is not being read in a simple loop,
|
|
234
|
+
# so "for ix, record in enumerate(p)" cannot easily be used. It is the
|
|
235
|
+
# number of the last record read or written. Wireshark numbers records
|
|
236
|
+
# starting at 1, so after the first record is read or written, rec_no
|
|
237
|
+
# will be 1
|
|
238
|
+
self.rec_no = 0
|
|
239
|
+
|
|
240
|
+
self.fopen = None # make deterministic if the file open fails
|
|
188
241
|
try:
|
|
189
242
|
self.fopen = open(filename, f"{self.mode}b", self._bufferring)
|
|
190
243
|
except Exception as e:
|
|
191
244
|
raise IOError(f"Failed to open {self.filename}. err={e}")
|
|
192
245
|
|
|
246
|
+
# mode can be anything that open() will accept with 'b' added. So it
|
|
247
|
+
# could be "a". But for "r" or "w", then the header must be handled.
|
|
193
248
|
if self.mode == "r":
|
|
194
249
|
self._read_global_header()
|
|
195
250
|
elif self.mode == "w":
|
|
@@ -200,6 +255,13 @@ class Pcap(object):
|
|
|
200
255
|
except Exception as e:
|
|
201
256
|
self.filesize = 0
|
|
202
257
|
|
|
258
|
+
# Define __enter__() and __exit__() so "with Pcap(...) as x" can be used
|
|
259
|
+
def __enter__(self):
|
|
260
|
+
return self
|
|
261
|
+
|
|
262
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
263
|
+
self.close()
|
|
264
|
+
|
|
203
265
|
def flush(self):
|
|
204
266
|
return self.fopen.flush()
|
|
205
267
|
|
|
@@ -254,6 +316,7 @@ class Pcap(object):
|
|
|
254
316
|
|
|
255
317
|
_pkt = pcaprecord.pack()
|
|
256
318
|
self.fopen.write(_pkt)
|
|
319
|
+
self.rec_no += 1
|
|
257
320
|
self.filesize += len(_pkt)
|
|
258
321
|
|
|
259
322
|
def close(self):
|
|
@@ -280,6 +343,7 @@ class Pcap(object):
|
|
|
280
343
|
except:
|
|
281
344
|
raise StopIteration
|
|
282
345
|
else:
|
|
346
|
+
self.rec_no += 1
|
|
283
347
|
return pcaprecord
|
|
284
348
|
|
|
285
349
|
__next__ = next
|
|
@@ -111,5 +111,9 @@
|
|
|
111
111
|
# 1.2.4 - Removed exit in the ch7
|
|
112
112
|
# 1.2.5 - Added C implementation of Golay. Also improved the existing python impl
|
|
113
113
|
# 1.2.6 - Further optimisation of the C Golay implementation
|
|
114
|
-
# 1.2.7 -
|
|
115
|
-
|
|
114
|
+
# 1.2.7 - Changed setup so as not to break if extension cannot be compiled
|
|
115
|
+
# 1.2.8 (FJP 2025-07-01)
|
|
116
|
+
# - Added Context Manager support to Pcap.py
|
|
117
|
+
# - Allow Golay.decode() to accept bytearray or other bytes-like object instead of only bytes (if not int)
|
|
118
|
+
# - simplified Golay.py; removed some redundant checks
|
|
119
|
+
__version__ = "1.2.8"
|