Beispiel #1
0
def test_client_addresses(monkeypatch, protocol, default_port, env_auto,
                          env_addr, expected):
    env = ca.get_environment_variables()

    # Easier to test without netifaces
    monkeypatch.setattr(ca._utils, 'netifaces', None)

    env[f'EPICS_{protocol}_ADDR_LIST'] = env_addr
    env[f'EPICS_{protocol}_AUTO_ADDR_LIST'] = env_auto
    if protocol == 'CA':
        env['EPICS_CA_SERVER_PORT'] = int(default_port)
    elif protocol == 'PVA':
        env['EPICS_PVA_BROADCAST_PORT'] = int(default_port)

    patch_env(monkeypatch, env)
    assert set(ca.get_client_address_list(protocol=protocol)) == set(expected)
Beispiel #2
0
def search(pv_name, udp_sock, timeout, *, max_retries=2):
    # Set Broadcaster log level to match our logger.
    b = ca.Broadcaster(our_role=ca.CLIENT)
    b.client_address = safe_getsockname(udp_sock)

    # Send registration request to the repeater
    logger.debug('Registering with the Channel Access repeater.')
    bytes_to_send = b.send(ca.RepeaterRegisterRequest())

    env = get_environment_variables()
    repeater_port = env['EPICS_CA_REPEATER_PORT']

    client_address_list = ca.get_client_address_list()
    local_address = ca.get_local_address()

    try:
        udp_sock.sendto(bytes_to_send, (local_address, repeater_port))
    except OSError as exc:
        raise ca.CaprotoNetworkError(
            f"Failed to send to {local_address}:{repeater_port}") from exc

    logger.debug("Searching for %r....", pv_name)
    commands = (ca.VersionRequest(0, ca.DEFAULT_PROTOCOL_VERSION),
                ca.SearchRequest(pv_name, 0, ca.DEFAULT_PROTOCOL_VERSION))
    bytes_to_send = b.send(*commands)
    tags = {
        'role': 'CLIENT',
        'our_address': b.client_address,
        'direction': '--->>>'
    }

    def send_search():
        for dest in client_address_list:
            tags['their_address'] = dest
            b.log.debug('%d commands %dB',
                        len(commands),
                        len(bytes_to_send),
                        extra=tags)
            try:
                udp_sock.sendto(bytes_to_send, dest)
            except OSError as exc:
                host, port = dest
                raise ca.CaprotoNetworkError(
                    f"Failed to send to {host}:{port}") from exc

    def check_timeout():
        nonlocal retry_at

        if time.monotonic() >= retry_at:
            send_search()
            retry_at = time.monotonic() + retry_timeout

        if time.monotonic() - t > timeout:
            raise CaprotoTimeoutError(
                f"Timed out while awaiting a response "
                f"from the search for {pv_name!r}. Search "
                f"requests were sent to this address list: "
                f"{ca.get_address_list()}.")

    # Initial search attempt
    send_search()

    # Await a search response, and keep track of registration status
    retry_timeout = timeout / max((max_retries, 1))
    t = time.monotonic()
    retry_at = t + retry_timeout

    try:
        orig_timeout = udp_sock.gettimeout()
        udp_sock.settimeout(retry_timeout)
        while True:
            try:
                bytes_received, address = udp_sock.recvfrom(ca.MAX_UDP_RECV)
            except socket.timeout:
                check_timeout()
                continue

            check_timeout()

            commands = b.recv(bytes_received, address)
            b.process_commands(commands)
            for command in commands:
                if isinstance(command, ca.SearchResponse) and command.cid == 0:
                    address = ca.extract_address(command)
                    logger.debug('Found %r at %s:%d', pv_name, *address)
                    return address
            else:
                # None of the commands we have seen are a reply to our request.
                # Receive more data.
                continue
    finally:
        udp_sock.settimeout(orig_timeout)
Beispiel #3
0
 def send_search(message):
     bytes_to_send = broadcaster.send(message)
     for host, port in get_client_address_list(protocol='PVA'):
         udp_sock.sendto(bytes_to_send, (host, port))
         logger.debug('Search request sent to %r.', (host, port))
         logger.debug('%s', bytes_to_send)