# Buggy code
def parse_services(message: DnsMessage) -> typing.List[Service]:
    """Parse DNS response into Service objects."""
    table: typing.Dict[str, typing.Dict[int, DnsResource]] = {}
    ptrs: typing.Dict[str, str] = {}  # qname -> real name
    results: typing.Dict[str, Service] = {}

    # Create a global table with all records
    for record in message.answers + message.resources:
        if record.qtype == QueryType.PTR and record.qname.startswith("_"):
            ptrs[record.qname] = record.rd
        else:
            table.setdefault(record.qname, {})[record.qtype] = record

    # Build services
    for service, device in table.items():
        service_name, _, service_type = service.partition(".")

        if not service_type.endswith("_tcp.local"):
            continue

        port = (QueryType.SRV in device and device[QueryType.SRV].rd["port"]) or 0
        target = (
            QueryType.SRV in device and device[QueryType.SRV].rd["target"]
        ) or None
        properties = (QueryType.TXT in device and device[QueryType.TXT].rd) or {}

        target_record = table.get(typing.cast(str, target), {}).get(QueryType.A)
        address = IPv4Address(target_record.rd) if target_record else None

        results[service] = Service(
            service_type,
            service_name,
            address,
            port,
            _decode_properties(properties),
        )

    # If there are PTRs to unknown services, create placeholders
    for qname, real_name in ptrs.items():
        if real_name not in results:
            results[real_name] = Service(qname, real_name.split(".")[0], None, 0, {})

    return list(results.values())


# Traceback (UnicodeDecodeError)
$  atvremote --debug --mdns-debug scan
...
2021-01-09 22:15:43 ERROR: bad stuff
Traceback (most recent call last):
File "/home/postlund/pyatv_dev/pyatv/pyatv/support/mdns.py", line 337, in datagram_received
services = parse_services(DnsMessage().unpack(data))
File "/home/postlund/pyatv_dev/pyatv/pyatv/support/dns.py", line 291, in unpack
self.answers.extend(
File "/home/postlund/pyatv_dev/pyatv/pyatv/support/dns.py", line 292, in <genexpr>
DnsResource.unpack_read(buffer) for _ in range((header.ancount))
File "/home/postlund/pyatv_dev/pyatv/pyatv/support/dns.py", line 258, in unpack_read
rd = qtype.parse_rdata(buffer, rd_length)
File "/home/postlund/pyatv_dev/pyatv/pyatv/support/dns.py", line 173, in parse_rdata
return parse_domain_name(buffer)
File "/home/postlund/pyatv_dev/pyatv/pyatv/support/dns.py", line 108, in parse_domain_name
return ".".join(label.decode("idna") for label in labels)
File "/home/postlund/pyatv_dev/pyatv/pyatv/support/dns.py", line 108, in <genexpr>
return ".".join(label.decode("idna") for label in labels)
File "/usr/local/lib/python3.8/encodings/idna.py", line 214, in decode
result.append(ToUnicode(label))
File "/usr/local/lib/python3.8/encodings/idna.py", line 125, in ToUnicode
return str(label, "ascii")
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 5: ordinal not in range(128)
2021-01-09 22:15:43 DEBUG: Failed to decode message (Msg=35ff840000030003000000000b5f6170706c6574762d7632045f746370056c6f63616c00000c80010b5f746f7563682d61626c65c018000c8001085f616972706c6179c018000c8001c028000c00010000000a00131032444632453735303736333943323639c028c00c000c00010000000a00131032444632453735303736333943323639c00cc03a000c00010000000a0013104170706c65c2a0545620283431363729c03a)
...

# Fixed code
def parse_services(message: DnsMessage) -> typing.List[Service]:
    """Parse DNS response into Service objects."""
    table: typing.Dict[str, typing.Dict[int, DnsResource]] = {}
    ptrs: typing.Dict[str, str] = {}  # qname -> real name
    results: typing.Dict[str, Service] = {}

    # Create a global table with all records
    for record in message.answers + message.resources:
        if record.qtype == QueryType.PTR and record.qname.startswith("_"):
            ptrs[record.qname] = record.rd
        else:
            table.setdefault(record.qname, {})[record.qtype] = record

    # Build services
    for service, device in table.items():
        try:
            service_name = ServiceInstanceName.split_name(service)
        except ValueError:
            continue

        port = (QueryType.SRV in device and device[QueryType.SRV].rd["port"]) or 0
        target = (
            QueryType.SRV in device and device[QueryType.SRV].rd["target"]
        ) or None
        properties = (QueryType.TXT in device and device[QueryType.TXT].rd) or {}

        target_record = table.get(typing.cast(str, target), {}).get(QueryType.A)
        address = IPv4Address(target_record.rd) if target_record else None

        results[service] = Service(
            service_name.ptr_name,
            typing.cast(str, service_name.instance),
            address,
            port,
            _decode_properties(properties),
        )

    # If there are PTRs to unknown services, create placeholders
    for qname, real_name in ptrs.items():
        if real_name not in results:
            results[real_name] = Service(qname, real_name.split(".")[0], None, 0, {})

    return list(results.values())