Open a port for the raiden service (listening at `internal_port`) through
    UPnP.

    Args:
        internal_port (int): the target port of the raiden service
        external_start_port (int): query for an external port starting here
            (default: internal_port)
    Returns:
        external_ip_address, external_port (tuple(str, int)): if successful or None

def open_port(upnp, internal_port, external_start_port=None):
    """Open a port for the raiden service (listening at `internal_port`) through
    UPnP.

    Args:
        internal_port (int): the target port of the raiden service
        external_start_port (int): query for an external port starting here
            (default: internal_port)
    Returns:
        external_ip_address, external_port (tuple(str, int)): if successful or None
    """
    if external_start_port is None:
        external_start_port = internal_port

    if upnp is None:
        return False

    def register(internal, external):
        # test existing mappings
        mapping = upnp.getspecificportmapping(external, 'UDP')
        if mapping is not None:
            # FIXME: figure out semantics of the last two values
            lanaddr, internal_mapped, name, _, _ = mapping

            is_valid_mapping = (
                lanaddr == upnp.lanaddr and
                name == RAIDEN_IDENTIFICATOR and
                internal_mapped == internal
            )
            is_not_our_mapping = (
                internal_mapped != internal and
                name != RAIDEN_IDENTIFICATOR
            )
            is_previous_mapping = (
                internal_mapped != internal and
                name == RAIDEN_IDENTIFICATOR and
                lanaddr == upnp.lanaddr
            )
            if is_valid_mapping:
                log.debug(
                    'keeping pre-existing portmapping',
                    internal=internal,
                    external=external,
                    lanaddr=lanaddr,
                )
                return True
            elif lanaddr != upnp.lanaddr:
                # don't touch other people's mappings
                log.debug(
                    'ignoring existing mapping for other IP',
                    internal=internal,
                    external=external,
                    other_ip=lanaddr,
                    our_ip=upnp.lanaddr,
                )
                return False
            elif is_not_our_mapping:
                log.debug(
                    'ignoring existing mapping for other program',
                    name=name,
                )
                # some other program uses our port
                return False
            elif is_previous_mapping:
                # we ran before on a different internal port
                log.debug('releasing previous port mapping')
                upnp.deleteportmapping(external, 'UDP')

        log.debug('trying to create new port mapping', internal=internal, external=external)
        return upnp.addportmapping(
            external,
            'UDP',
            upnp.lanaddr,
            internal,
            RAIDEN_IDENTIFICATOR,
            '',
        )

    external_port = external_start_port
    success = register(internal_port, external_port)
    while not success and external_port <= MAX_PORT:
        external_port += 1
        log.debug('trying', external=external_port)
        success = register(internal_port, external_port)

    if success:
        return upnp.externalipaddress(), external_port
    else:
        log.error(
            'could not register a port-mapping',
            location='FIXME',
        )
        return False

    return False