async def _bind_tcp_sockets_with_consistent_port_number(self, make_socket): # Find a random port number that is free on all self.interfaces, # and get a bound TCP socket with that port number on each # interface. The argument `make_socket` is expected to be a coroutine # with the signature `make_socket(interface, port)` that does whatever # library-specific incantation is necessary to return a bound socket or # raise an IOError. tcp_sockets = {} # maps interface to bound socket stashed_ex = None for port in ca.random_ports(100, try_first=self.ca_server_port): try: for interface in self.interfaces: s = await make_socket(interface, port) tcp_sockets[interface] = s except IOError as ex: stashed_ex = ex for s in tcp_sockets.values(): s.close() tcp_sockets.clear() else: break else: raise CaprotoRuntimeError( 'No available ports and/or bind failed') from stashed_ex return port, tcp_sockets
def __init__(self, pvname, callback=None, form='time', verbose=False, auto_monitor=None, count=None, connection_callback=None, connection_timeout=None, access_callback=None, *, context=None): if context is None: context = self._default_context if context is None: raise CaprotoRuntimeError("must have a valid context") self._context = context self.pvname = pvname.strip() self.form = form.lower() self.verbose = verbose self.auto_monitor = auto_monitor self.ftype = None self._connected = False self._connect_event = threading.Event() self._state_lock = threading.RLock() self.connection_timeout = connection_timeout self.default_count = count self._auto_monitor_sub = None if self.connection_timeout is None: self.connection_timeout = 1 self._args = {}.fromkeys(self._fields) self._args['pvname'] = self.pvname self._args['count'] = count self._args['nelm'] = -1 self._args['type'] = None self._args['typefull'] = None self._args['access'] = None self.connection_callbacks = [] self._cb_count = iter(itertools.count()) if connection_callback is not None: self.connection_callbacks = [connection_callback] self.access_callbacks = [] if access_callback is not None: self.access_callbacks.append(access_callback) self.callbacks = {} self._conn_started = False if isinstance(callback, (tuple, list)): for i, thiscb in enumerate(callback): if hasattr(thiscb, '__call__'): self.callbacks[i] = (thiscb, {}) elif hasattr(callback, '__call__'): self.callbacks[0] = (callback, {}) self._caproto_pv, = self._context.get_pvs( self.pvname, connection_state_callback=self._connection_state_changed, access_rights_callback=self._access_rights_changed, ) if self._caproto_pv.connected: # connection state callback was already called but we didn't see it self._connection_state_changed(self._caproto_pv, 'connected')