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
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)
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))
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()
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
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))
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
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 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
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))
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)
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
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
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)
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()
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)