Exemplo n.º 1
0
def test_broadcast_address_list_from_interfaces():
    # Smoke test broadcast_address_list_from_interfaces by setting the right
    # env vars and calling get_address_list.
    env = os.environ.copy()
    try:
        os.environ['EPICS_CA_AUTO_ADDR_LIST'] = 'YES'
        ca.get_address_list()
    finally:
        os.environ = env
Exemplo n.º 2
0
def test_env_util_smoke(protocol):
    ca.get_environment_variables()
    try:
        ca.get_netifaces_addresses()
    except RuntimeError:
        # Netifaces may be unavailable
        ...

    ca.get_address_list(protocol=protocol)
    ca.get_beacon_address_list(protocol=protocol)
    ca._utils.get_manually_specified_beacon_addresses(protocol=protocol)
    ca._utils.get_manually_specified_client_addresses(protocol=protocol)
    ca.get_server_address_list(protocol=protocol)
Exemplo n.º 3
0
 async def send(self, port, *commands):
     """
     Process a command and tranport it over the UDP socket.
     """
     bytes_to_send = self.broadcaster.send(*commands)
     for host in ca.get_address_list():
         if ':' in host:
             host, _, specified_port = host.partition(':')
             is_register = isinstance(commands[0],
                                      ca.RepeaterRegisterRequest)
             if not self.registered and is_register:
                 logger.debug(
                     'Specific IOC host/port designated in address'
                     'list: %s:%s.  Repeater registration '
                     'requirement ignored', host, specified_port)
                 async with self.broadcaster_command_condition:
                     # TODO how does this work with multiple addresses
                     # listed?
                     response = (('127.0.0.1', ca.EPICS_CA1_PORT), [
                         ca.RepeaterConfirmResponse(
                             repeater_address='127.0.0.1')
                     ])
                     await self.command_bundle_queue.put(response[1])
                     await self.broadcaster_command_condition.notify_all()
                 continue
             await self.udp_sock.sendto(bytes_to_send,
                                        (host, int(specified_port)))
         else:
             await self.udp_sock.sendto(bytes_to_send, (host, port))
Exemplo n.º 4
0
def test_specified_port(monkeypatch, context, ioc):
    pv, = context.get_pvs(ioc.pvs['float'])
    pv.wait_for_connection(timeout=10)

    circuit = pv.circuit_manager.circuit
    address_list = list(caproto.get_address_list())
    address_list.append('{}:{}'.format(circuit.host, circuit.port))

    def get_address_list():
        return address_list

    for module in (caproto._utils, caproto, caproto.threading.client):
        if hasattr(module, 'get_address_list'):
            print('patching', module)
            monkeypatch.setattr(module, 'get_address_list', get_address_list)

    print()
    print('- address list is now:', address_list)
    shared_broadcaster = SharedBroadcaster()
    new_context = Context(shared_broadcaster)
    pv1, = new_context.get_pvs(ioc.pvs['float'])
    pv1.wait_for_connection()
    assert pv1.connected
    pv1.read()
    new_context.disconnect()
Exemplo n.º 5
0
 async def send(self, port, *commands):
     """
     Process a command and tranport it over the UDP socket.
     """
     bytes_to_send = self.broadcaster.send(*commands)
     tags = {
         'role': 'CLIENT',
         'our_address': self.broadcaster.client_address,
         'direction': '--->>>'
     }
     for host in ca.get_address_list():
         if ':' in host:
             host, _, port_as_str = host.partition(':')
             specified_port = int(port_as_str)
         else:
             specified_port = port
         tags['their_address'] = (host, specified_port)
         self.broadcaster.log.debug('%d commands %dB',
                                    len(commands),
                                    len(bytes_to_send),
                                    extra=tags)
         try:
             await self.udp_sock.sendto(bytes_to_send,
                                        (host, specified_port))
         except OSError as ex:
             raise ca.CaprotoNetworkError(
                 f'{ex} while sending {len(bytes_to_send)} bytes to '
                 f'{host}:{specified_port}') from ex
Exemplo n.º 6
0
 def send(self, port, *commands):
     """
     Process a command and tranport it over the UDP socket.
     """
     with self.command_cond:
         bytes_to_send = self.broadcaster.send(*commands)
         for host in ca.get_address_list():
             self.udp_sock.sendto(bytes_to_send, (host, port))
Exemplo n.º 7
0
def test_broadcast_auto_address_list():
    env = os.environ.copy()
    try:
        os.environ['EPICS_CA_ADDR_LIST'] = ''
        os.environ['EPICS_CA_AUTO_ADDR_LIST'] = 'YES'
        assert ca.get_address_list() == ['255.255.255.255']
    finally:
        os.environ = env
Exemplo n.º 8
0
 def send_search():
     for host in ca.get_address_list():
         if ':' in host:
             host, _, specified_port = host.partition(':')
             dest = (host, int(specified_port))
         else:
             dest = (host, CA_SERVER_PORT)
         udp_sock.sendto(bytes_to_send, dest)
         logger.debug('Search request sent to %r.', dest)
Exemplo n.º 9
0
def test_broadcast_auto_address_list():
    pytest.importorskip('netifaces')
    env = os.environ.copy()
    try:
        os.environ['EPICS_CA_ADDR_LIST'] = ''
        os.environ['EPICS_CA_AUTO_ADDR_LIST'] = 'YES'
        expected = [bcast for addr, bcast in ca.get_netifaces_addresses()]
        assert ca.get_address_list() == expected
    finally:
        os.environ = env
Exemplo n.º 10
0
 async def send(self, port, *commands):
     """
     Process a command and tranport it over the UDP socket.
     """
     bytes_to_send = self.broadcaster.send(*commands)
     for host in ca.get_address_list():
         if ':' in host:
             host, _, specified_port = host.partition(':')
             await self.udp_sock.sendto(bytes_to_send,
                                        (host, int(specified_port)))
         else:
             await self.udp_sock.sendto(bytes_to_send, (host, port))
Exemplo n.º 11
0
 def send_search():
     for host in ca.get_address_list():
         if ':' in host:
             host, _, specified_port = host.partition(':')
             dest = (host, int(specified_port))
         else:
             dest = (host, CA_SERVER_PORT)
         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
         logger.debug('Search request sent to %r.', dest)
Exemplo n.º 12
0
 def send_search():
     for host in ca.get_address_list():
         if ':' in host:
             host, _, specified_port = host.partition(':')
             dest = (host, int(specified_port))
         else:
             dest = (host, CA_SERVER_PORT)
         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
Exemplo n.º 13
0
 async def send(self, port, *commands):
     """
     Process a command and tranport it over the UDP socket.
     """
     bytes_to_send = self.broadcaster.send(*commands)
     for host in ca.get_address_list():
         if ':' in host:
             host, _, port_as_str = host.partition(':')
             specified_port = int(port_as_str)
         else:
             specified_port = port
         self.broadcaster.log.debug('Sending %d bytes to %s:%d',
                                    len(bytes_to_send), host,
                                    specified_port)
         try:
             await self.udp_sock.sendto(bytes_to_send,
                                        (host, specified_port))
         except OSError as ex:
             raise ca.CaprotoNetworkError(
                 f'{ex} while sending {len(bytes_to_send)} bytes to '
                 f'{host}:{specified_port}') from ex
Exemplo n.º 14
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)

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

    repeater_port = os.environ.get('EPICS_CA_REPEATER_PORT', 5065)
    for host in ca.get_address_list():
        udp_sock.sendto(bytes_to_send, (host, repeater_port))

    logger.debug("Searching for '%s'....", pv_name)
    bytes_to_send = b.send(
        ca.VersionRequest(0, ca.DEFAULT_PROTOCOL_VERSION),
        ca.SearchRequest(pv_name, 0, ca.DEFAULT_PROTOCOL_VERSION))

    def send_search():
        for host in ca.get_address_list():
            if ':' in host:
                host, _, specified_port = host.partition(':')
                dest = (host, int(specified_port))
            else:
                dest = (host, CA_SERVER_PORT)
            udp_sock.sendto(bytes_to_send, dest)
            logger.debug('Search request sent to %r.', dest)

    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 TimeoutError(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 %s at %s', 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)
Exemplo n.º 15
0
def main(*, skip_monitor_section=False):
    # A broadcast socket
    udp_sock = ca.bcast_socket()

    # Register with the repeater.
    bytes_to_send = b.send(ca.RepeaterRegisterRequest('0.0.0.0'))

    # TODO: for test environment with specific hosts listed in
    # EPICS_CA_ADDR_LIST
    if False:
        fake_reg = (('127.0.0.1', ca.EPICS_CA1_PORT),
                    [ca.RepeaterConfirmResponse(repeater_address='127.0.0.1')])
        b.command_queue.put(fake_reg)
    else:
        udp_sock.sendto(bytes_to_send, ('', CA_REPEATER_PORT))

        # Receive response
        data, address = udp_sock.recvfrom(1024)
        commands = b.recv(data, address)

    b.process_commands(commands)

    # Search for pv1.
    # CA requires us to send a VersionRequest and a SearchRequest bundled into
    # one datagram.
    bytes_to_send = b.send(ca.VersionRequest(0, 13),
                           ca.SearchRequest(pv1, 0, 13))
    for host in ca.get_address_list():
        if ':' in host:
            host, _, specified_port = host.partition(':')
            udp_sock.sendto(bytes_to_send, (host, int(specified_port)))
        else:
            udp_sock.sendto(bytes_to_send, (host, CA_SERVER_PORT))
    print('searching for %s' % pv1)
    # Receive a VersionResponse and SearchResponse.
    bytes_received, address = udp_sock.recvfrom(1024)
    commands = b.recv(bytes_received, address)
    b.process_commands(commands)
    c1, c2 = commands
    assert type(c1) is ca.VersionResponse
    assert type(c2) is ca.SearchResponse
    address = ca.extract_address(c2)

    circuit = ca.VirtualCircuit(our_role=ca.CLIENT,
                                address=address,
                                priority=0)
    circuit.log.setLevel('DEBUG')
    chan1 = ca.ClientChannel(pv1, circuit)
    sockets[chan1.circuit] = socket.create_connection(chan1.circuit.address)

    # Initialize our new TCP-based CA connection with a VersionRequest.
    send(chan1.circuit, ca.VersionRequest(priority=0, version=13))
    recv(chan1.circuit)
    # Send info about us.
    send(chan1.circuit, ca.HostNameRequest('localhost'))
    send(chan1.circuit, ca.ClientNameRequest('username'))
    send(chan1.circuit,
         ca.CreateChanRequest(name=pv1, cid=chan1.cid, version=13))
    commands = recv(chan1.circuit)

    # Test subscriptions.
    assert chan1.native_data_type and chan1.native_data_count
    add_req = ca.EventAddRequest(data_type=chan1.native_data_type,
                                 data_count=chan1.native_data_count,
                                 sid=chan1.sid,
                                 subscriptionid=0,
                                 low=0,
                                 high=0,
                                 to=0,
                                 mask=1)
    send(chan1.circuit, add_req)

    commands = recv(chan1.circuit)

    if not skip_monitor_section:
        try:
            print('Monitoring until Ctrl-C is hit. Meanwhile, use caput to '
                  'change the value and watch for commands to arrive here.')
            while True:
                commands = recv(chan1.circuit)
                if commands:
                    print(commands)
        except KeyboardInterrupt:
            pass

    cancel_req = ca.EventCancelRequest(data_type=add_req.data_type,
                                       sid=add_req.sid,
                                       subscriptionid=add_req.subscriptionid)

    send(chan1.circuit, cancel_req)
    commands, = recv(chan1.circuit)

    # Test reading.
    send(
        chan1.circuit,
        ca.ReadNotifyRequest(data_type=2, data_count=1, sid=chan1.sid,
                             ioid=12))
    commands, = recv(chan1.circuit)

    # Test writing.
    request = ca.WriteNotifyRequest(data_type=2,
                                    data_count=1,
                                    sid=chan1.sid,
                                    ioid=13,
                                    data=(4, ))

    send(chan1.circuit, request)
    recv(chan1.circuit)
    time.sleep(2)
    send(
        chan1.circuit,
        ca.ReadNotifyRequest(data_type=2, data_count=1, sid=chan1.sid,
                             ioid=14))
    recv(chan1.circuit)

    # Test "clearing" (closing) the channel.
    send(chan1.circuit, ca.ClearChannelRequest(chan1.sid, chan1.cid))
    recv(chan1.circuit)

    sockets.pop(chan1.circuit).close()
    udp_sock.close()
Exemplo n.º 16
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())

    repeater_port = get_environment_variables()['EPICS_CA_REPEATER_PORT']
    for host in ca.get_address_list():
        try:
            udp_sock.sendto(bytes_to_send, (host, repeater_port))
        except OSError as exc:
            raise ca.CaprotoNetworkError(
                f"Failed to send to {host}:{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 host in ca.get_address_list():
            if ':' in host:
                host, _, specified_port = host.partition(':')
                dest = (host, int(specified_port))
            else:
                dest = (host, CA_SERVER_PORT)
            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)