dbus-pcap: Parse headers of large messages

When encountering a large message that got truncated, instead of
raising a MalformedPacketError and completely ignoring the message,
parse as much as possible (in this case, its header) so that it can
still be used for certain purposes, such as to match method calls and
method returns.

Tested: compared against WireShark outputs (WireShark is able to handle
truncated messages) and manually inspecting parsed results.

One example message:
  CookedMessage(header=CookedHeader(fixed=FixedHeader(endian=108, type=2,
  flags=1, version=1, length=125272, cookie=3543),
  fields=[Field(type=<MessageFieldType.REPLY_SERIAL: 5>, data=2),
  Field(type=<MessageFieldType.DESTINATION: 6>, data=':1.1145'),
  Field(type=<MessageFieldType.SIGNATURE: 8>, data='a{oa{sa{sv}}}'),
  Field(type=<MessageFieldType.SENDER: 7>, data=':1.628')]), body=[])

Signed-off-by: Sui Chen <suichen@google.com>
Change-Id: Ie415735aef2b1c0bf6f27c509684964ccd87d1d9
diff --git a/dbus-pcap/dbus-pcap b/dbus-pcap/dbus-pcap
index c6ed792..3c797e0 100755
--- a/dbus-pcap/dbus-pcap
+++ b/dbus-pcap/dbus-pcap
@@ -290,14 +290,14 @@
 class MalformedPacketError(Exception):
     pass
 
-def parse_header(raw):
+def parse_header(raw, ignore_error):
     assert raw.endian in StructEndianLookup.keys()
     endian = StructEndianLookup[raw.endian]
     fixed = FixedHeader._make(struct.unpack("{}BBBBLL".format(endian), raw.header))
     astream = AlignedStream(raw.data, len(raw.header))
     fields = parse_fields(endian, astream)
     data, offset = astream.drain()
-    if fixed.length > len(data):
+    if ignore_error == False and fixed.length > len(data):
         raise MalformedPacketError
     return CookedHeader(fixed, fields), AlignedStream(data, offset)
 
@@ -320,7 +320,7 @@
 
 def parse_message(raw):
     try:
-        header, data = parse_header(raw)
+        header, data = parse_header(raw, False)
         try:
             body = parse_body(header, data)
             return CookedMessage(header, body)
@@ -333,7 +333,14 @@
 
 def parse_packet(packet):
     data = bytes(packet)
-    msg = parse_message(RawMessage(data[0], data[:12], data[12:]))
+    raw = RawMessage(data[0], data[:12], data[12:])
+    try:
+        msg = parse_message(raw)
+    except MalformedPacketError as e:
+        # For a message that is so large that its payload data could not be parsed,
+        # just parse its header, then set its data field to empty.
+        header, data = parse_header(raw, True)
+        msg = CookedMessage(header, [])
     return msg
 
 CallEnvelope = namedtuple("CallEnvelope", "cookie, origin")