Beispiel #1
0
    def test_get_local_addresses(self):
        # mostly a tripwire test
        from rosgraph.network import get_local_addresses
        addrs = get_local_addresses()
        assert type(addrs) == list
        assert len(addrs)

        # should be unaffected
        os.environ['ROS_IP'] = 'bar'
        assert addrs == get_local_addresses()
        os.environ['ROS_HOSTNAME'] = 'foo'
        assert addrs == get_local_addresses()
 def test_get_local_addresses(self):
     # mostly a tripwire test
     from rosgraph.network import get_local_addresses
     addrs = get_local_addresses()
     assert type(addrs) == list
     assert len(addrs)
 
     # should be unaffected
     os.environ['ROS_IP'] = 'bar'
     assert addrs == get_local_addresses()
     os.environ['ROS_HOSTNAME'] = 'foo'
     assert addrs == get_local_addresses()
Beispiel #3
0
def __is_local(hostname):
    '''
    Test the hostname whether it is local or not. Uses socket.gethostbyname().
    '''
    try:
        # If Python has ipv6 disabled but machine.address can be resolved somehow to an ipv6 address, then host[4][0] will be int
        machine_ips = [
            host[4][0]
            for host in socket.getaddrinfo(hostname, 0, 0, 0, socket.SOL_TCP)
            if isinstance(host[4][0], str)
        ]
    except socket.gaierror:
        with _LOCK:
            rospy.logdebug("host::HOSTS_CACHE resolve %s failed" % hostname)
            HOSTS_CACHE[hostname] = False
        return False
    local_addresses = ['localhost'] + get_local_addresses()
    # check 127/8 and local addresses
    result = ([
        ip for ip in machine_ips if (ip.startswith('127.') or ip == '::1')
    ] != []) or (set(machine_ips) & set(local_addresses) != set())
    with _LOCK:
        rospy.logdebug("host::HOSTS_CACHE add %s:%s" % (hostname, result))
        HOSTS_CACHE[hostname] = result
    return result
Beispiel #4
0
 def __is_local(cls, hostname):
     try:
         machine_addr = socket.gethostbyname(hostname)
     except socket.gaierror:
         import traceback
         print(traceback.format_exc())
         return False
     local_addresses = ['localhost'] + get_local_addresses()
     # check 127/8 and local addresses
     result = machine_addr.startswith('127.') or machine_addr in local_addresses
     return result
Beispiel #5
0
    def __init__(self, interface, port):
        '''
        Creates a socket, bind it to a given interface+port for unicast send/receive.
        IPv4 and IPv6 are supported.
        @param interface: The interface to bind to
        @type interface: str
        @param port: the port to bind the socket
        @type port: int
        '''
        self.interface = interface
        self.port = port
        addrinfo = None
        # If interface isn't specified, try to find an non localhost interface to
        # get some info for binding. Otherwise use localhost
        if not self.interface:
            ifaces = get_local_addresses()
            self.interface = 'localhost'
            for iface in ifaces:
                if not (iface.startswith('127') or iface.startswith('::1')):
                    self.interface = iface
                    break
            rospy.loginfo("+ Bind to unicast socket @(%s:%s)", self.interface,
                          port)
            addrinfo = UcastSocket.getaddrinfo(self.interface)
        else:
            # Otherwise get the address info for the interface specified.
            rospy.loginfo("+ Bind to specified unicast socket @(%s:%s)",
                          self.interface, port)
            addrinfo = UcastSocket.getaddrinfo(self.interface)

        # Configure socket type
        socket.socket.__init__(self, addrinfo[0], socket.SOCK_DGRAM,
                               socket.IPPROTO_UDP)

        # Allow multiple copies of this program on one machine
        # Required to receive unicast UDP
        if hasattr(socket, "SO_REUSEPORT"):
            try:
                self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
            except:
                rospy.logwarn(
                    "SO_REUSEPORT failed: Protocol not available, some functions are not available."
                )

        # Bind to the port
        try:
            rospy.logdebug("Ucast bind to: (%s:%s)", addrinfo[4][0], port)
            self.bind((addrinfo[4][0], port))
        except socket.error as errobj:
            msg = str(errobj)
            rospy.logfatal(
                "Unable to bind unicast to interface: %s, check that it exists: %s",
                self.interface, msg)
            raise
Beispiel #6
0
def __is_local(hostname):
    '''
    Test the hostname whether it is local or not. Uses socket.gethostbyname().
    '''
    try:
        machine_addr = socket.gethostbyname(hostname)
    except socket.gaierror:
        with _LOCK:
            HOSTS_CACHE[hostname] = False
        return False
    local_addresses = ['localhost'] + get_local_addresses()
    # check 127/8 and local addresses
    result = machine_addr.startswith('127.') or machine_addr in local_addresses
    with _LOCK:
        HOSTS_CACHE[hostname] = result
    return result
Beispiel #7
0
def runNode(package, executable, name, args, prefix='', repawn=False, masteruri=None, loglevel=''):
    '''
    Runs a ROS node. Starts a roscore if needed.
    '''
    if not masteruri:
        masteruri = masteruri_from_ros()
    # start roscore, if needed
    nm.StartHandler._prepareROSMaster(masteruri)
    # start node
    try:
        cmd = roslib.packages.find_node(package, executable)
    except roslib.packages.ROSPkgException as e:
        # multiple nodes, invalid package
        raise nm.StartException(str(e))
    # handle different result types str or array of string (electric / fuerte)
    if isstring(cmd):
        cmd = [cmd]
    if cmd is None or len(cmd) == 0:
        raise nm.StartException(' '.join([executable, 'in package [', package, '] not found!\n\nThe package was created?\nIs the binary executable?\n']))
    # create string for node parameter. Set arguments with spaces into "'".
    node_params = ' '.join(''.join(["'", a, "'"]) if a.find(' ') > -1 else a for a in args[1:])
    cmd_args = [screen.get_cmd(name), RESPAWN_SCRIPT if repawn else '', prefix, cmd[0], node_params]
    print('run on remote host:', ' '.join(cmd_args))
    # determine the current working path
    arg_cwd = getCwdArg('__cwd', args)
    cwd = nm.get_ros_home()
    if not (arg_cwd is None):
        if arg_cwd == 'ROS_HOME':
            cwd = nm.get_ros_home()
        elif arg_cwd == 'node':
            cwd = os.path.dirname(cmd[0])
    # set the masteruri to launch with other one master
    new_env = dict(os.environ)
    new_env['ROS_MASTER_URI'] = masteruri
    ros_hostname = nmdhost.get_ros_hostname(masteruri)
    if ros_hostname:
        addr = socket.gethostbyname(ros_hostname)
        if addr in set(ip for ip in get_local_addresses()):
            new_env['ROS_HOSTNAME'] = ros_hostname
    if loglevel:
        new_env['ROSCONSOLE_CONFIG_FILE'] = rosconsole_cfg_file(package)
    subprocess.Popen(shlex.split(str(' '.join(cmd_args))), cwd=cwd, env=new_env)
    if len(cmd) > 1:
        rospy.logwarn('Multiple executables are found! The first one was started! Exceutables:\n%s', str(cmd))
Beispiel #8
0
def is_local(hostname, wait=True):
    '''
    Test whether the given host name is the name of the local host or not.

    :param str hostname: the name or IP of the host
    :return: `True` if the hostname is local or None
    :rtype: bool
    :raise Exception: on errors while resolving host
    '''
    if not hostname:
        return True
    with _LOCK:
        if hostname in HOSTS_CACHE:
            if isinstance(HOSTS_CACHE[hostname], threading.Thread):
                return False
            return HOSTS_CACHE[hostname]
    try:
        socket.inet_aton(hostname)
        local_addresses = ['localhost'] + get_local_addresses()
        # check 127/8 and local addresses
        result = hostname.startswith(
            '127.') or hostname == '::1' or hostname in local_addresses
        with _LOCK:
            rospy.logdebug("host::HOSTS_CACHE add local %s:%s" %
                           (hostname, result))
            HOSTS_CACHE[hostname] = result
        return result
    except socket.error:
        # the hostname must be resolved => do it in a thread
        if wait:
            result = __is_local(hostname)
            return result
        else:
            thread = threading.Thread(target=__is_local, args=((hostname, )))
            thread.daemon = True
            with _LOCK:
                HOSTS_CACHE[hostname] = thread
            thread.start()
    return False
Beispiel #9
0
    def is_local(cls, hostname, wait=False):
        '''
        Test whether the given host name is the name of the local host or not.

        :param str hostname: the name or IP of the host
        :return: True if the hostname is local or None
        :rtype: bool
        :raise Exception: on errors while resolving host
        '''
        if (hostname is None):
            return True
        try:
            socket.inet_aton(hostname)
            local_addresses = ['localhost'] + get_local_addresses()
            # check 127/8 and local addresses
            result = hostname.startswith('127.') or hostname in local_addresses
            return result
        except socket.error:
            # the hostname must be resolved => do it in a thread
            if wait:
                result = cls.__is_local(hostname)
                return result
        return False
Beispiel #10
0
def run_node(startcfg):
    '''
    Start a node local or on specified host using a :class:`.startcfg.StartConfig`

    :param startcfg: start configuration e.g. returned by :meth:`create_start_config`
    :type startcfg: :class:`fkie_node_manager_daemon.startcfg.StartConfig`
    :raise exceptions.StartException: on errors
    :raise exceptions.BinarySelectionRequest: on multiple binaries
    :see: :meth:`fkie_node_manager.host.is_local`
    '''
    hostname = startcfg.hostname
    nodename = roslib.names.ns_join(startcfg.namespace, startcfg.name)
    if not hostname or host.is_local(hostname, wait=True):
        # run on local host
        # interpret arguments with path elements
        args = []
        for arg in startcfg.args:
            new_arg = arg
            if arg.startswith('$(find'):
                new_arg = interpret_path(arg)
                rospy.logdebug("interpret arg '%s' to '%s'" % (arg, new_arg))
            args.append(new_arg)
        # set name and namespace of the node
        if startcfg.name:
            args.append("__name:=%s" % startcfg.name)
        if startcfg.namespace:
            args.append("__ns:=%s" % startcfg.namespace)
        # add remap arguments
        for key, val in startcfg.remaps.items():
            args.append("%s:=%s" % (key, val))
        cmd_type = startcfg.binary_path
        # get binary path from package
        if not cmd_type:
            try:
                cmd = roslib.packages.find_node(startcfg.package, startcfg.binary)
            except (roslib.packages.ROSPkgException, rospkg.ResourceNotFound) as e:
                # multiple nodes, invalid package
                rospy.logwarn("resource not found: %s" % utf8(e))
                raise exceptions.ResourceNotFound(startcfg.package, "resource not found: %s" % utf8(e))
            if isstring(cmd):
                cmd = [cmd]
            if cmd is None or len(cmd) == 0:
                raise exceptions.StartException('%s in package [%s] not found!' % (startcfg.binary, startcfg.package))
            if len(cmd) > 1:
                # Open selection for executables
                err = 'Multiple executables with same name in package [%s]  found:' % startcfg.package
                raise exceptions.BinarySelectionRequest(cmd, err)
            else:
                cmd_type = cmd[0]
        try:
            global STARTED_BINARIES
            STARTED_BINARIES[nodename] = (cmd_type, os.path.getmtime(cmd_type))
        except Exception:
            pass
        cwd = get_cwd(startcfg.cwd, cmd_type)
        # set environment
        new_env = dict(os.environ)
        # set display variable to local display
        if 'DISPLAY' in startcfg.env:
            if not startcfg.env['DISPLAY'] or startcfg.env['DISPLAY'] == 'remote':
                del startcfg.env['DISPLAY']
        #else:
        #    new_env['DISPLAY'] = ':0'
        # add environment from launch
        new_env.update(startcfg.env)
        if startcfg.namespace:
            new_env['ROS_NAMESPACE'] = startcfg.namespace
        # set logging
        if startcfg.logformat:
            new_env['ROSCONSOLE_FORMAT'] = '%s' % startcfg.logformat
        if startcfg.loglevel:
            new_env['ROSCONSOLE_CONFIG_FILE'] = _rosconsole_cfg_file(startcfg.package, startcfg.loglevel)
        # handle respawn
        if startcfg.respawn:
            if startcfg.respawn_delay > 0:
                new_env['RESPAWN_DELAY'] = '%d' % startcfg.respawn_delay
            respawn_params = _get_respawn_params(startcfg.fullname, startcfg.params)
            if respawn_params['max'] > 0:
                new_env['RESPAWN_MAX'] = '%d' % respawn_params['max']
            if respawn_params['min_runtime'] > 0:
                new_env['RESPAWN_MIN_RUNTIME'] = '%d' % respawn_params['min_runtime']
            cmd_type = "%s %s %s" % (settings.RESPAWN_SCRIPT, startcfg.prefix, cmd_type)
        else:
            cmd_type = "%s %s" % (startcfg.prefix, cmd_type)
        # check for masteruri
        masteruri = startcfg.masteruri
        if masteruri is None:
            masteruri = masteruri_from_ros()
        if masteruri is not None:
            if 'ROS_MASTER_URI' not in startcfg.env:
                new_env['ROS_MASTER_URI'] = masteruri
            # host in startcfg is a nmduri -> get host name
            ros_hostname = host.get_ros_hostname(masteruri, hostname)
            if ros_hostname:
                addr = socket.gethostbyname(ros_hostname)
                if addr in set(ip for _n, ip in get_local_addresses()):
                    new_env['ROS_HOSTNAME'] = ros_hostname
            # load params to ROS master
            _load_parameters(masteruri, startcfg.params, startcfg.clear_params)
        # start
        cmd_str = utf8('%s %s %s' % (screen.get_cmd(startcfg.fullname, new_env, list(startcfg.env.keys())), cmd_type, ' '.join(args)))
        rospy.loginfo("%s (launch_file: '%s', masteruri: %s)" % (cmd_str, startcfg.config_path, masteruri))
        rospy.logdebug("environment while run node '%s': '%s'" % (cmd_str, new_env))
        SupervisedPopen(shlex.split(cmd_str), cwd=cwd, env=new_env, object_id="run_node_%s" % startcfg.fullname, description="Run [%s]%s" % (utf8(startcfg.package), utf8(startcfg.binary)))
    else:
        nmduri = startcfg.nmduri
        rospy.loginfo("remote run node '%s' at '%s'" % (nodename, nmduri))
        startcfg.params.update(_params_to_package_path(startcfg.params))
        startcfg.args = _args_to_package_path(startcfg.args)
        # run on a remote machine
        channel = remote.get_insecure_channel(nmduri)
        if channel is None:
            raise exceptions.StartException("Unknown launch manager url for host %s to start %s" % (host, startcfg.fullname))
        lm = LaunchStub(channel)
        lm.start_standalone_node(startcfg)
Beispiel #11
0
    def __init__(self,
                 port,
                 mgroup,
                 ttl=20,
                 send_mcast=True,
                 listen_mcast=True):
        '''
        Creates a socket, bind it to a given port and join to a given multicast
        group. IPv4 and IPv6 are supported.
        @param port: the port to bind the socket
        @type port: int
        @param mgroup: the multicast group to join
        @type mgroup: str
        @param ttl: time to leave
        @type ttl: int (Default: 20)
        @param send_mcast: send multicast messages
        @type send_mcast: bool (Default: True)
        @param listen_mcast: listen to the multicast group
        @type listen_mcast: bool (Default: True)
        '''
        self.port = port
        self.receive_queue = queue.Queue()
        self._send_queue = queue.Queue()
        self._lock = threading.RLock()
        self.send_mcast = send_mcast
        self.listen_mcast = listen_mcast
        self.unicast_only = not (send_mcast or listen_mcast)
        self._closed = False
        self._locals = get_local_addresses()
        self._locals.append('localhost')
        self.sock_5_error_printed = []
        self.SOKET_ERRORS_NEEDS_RECONNECT = False
        # get the group and interface. Especially for definition like [email protected]
        # it also reads ~interface and ROS_IP
        self.mgroup, self.interface = DiscoverSocket.normalize_mgroup(
            mgroup, True)
        self.unicast_socket = None
        # get the AF_INET information for group to ensure that the address family
        # of group is the same as for interface
        addrinfo = UcastSocket.getaddrinfo(self.mgroup)
        self.interface_ip = ''
        if self.unicast_only:
            # inform about no braodcasting
            rospy.logwarn(
                "Multicast disabled! This master is only by unicast reachable!"
            )
        if self.interface:
            addrinfo = UcastSocket.getaddrinfo(self.interface, addrinfo[0])
            if addrinfo is not None:
                self.interface_ip = addrinfo[4][0]
                self.unicast_socket = UcastSocket(self.interface_ip, port)
        elif self.unicast_only:
            self.unicast_socket = UcastSocket('', port)

        rospy.logdebug("mgroup: %s", self.mgroup)
        rospy.logdebug("interface : %s", self.interface)
        rospy.logdebug("inet: %s", addrinfo)

        socket.socket.__init__(self, addrinfo[0], socket.SOCK_DGRAM,
                               socket.IPPROTO_UDP)
        self.addrinfo = addrinfo
        if not self.unicast_only:
            rospy.logdebug("Create multicast socket at ('%s', %d)",
                           self.mgroup, port)
            # initialize multicast socket
            # Allow multiple copies of this program on one machine
            if hasattr(socket, "SO_REUSEPORT"):
                try:
                    self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
                except:
                    rospy.logwarn(
                        "SO_REUSEPORT failed: Protocol not available, some functions are not available."
                    )
            # Set Time-to-live (optional) and loop count
            ttl_bin = struct.pack('@i', ttl)
            if addrinfo[0] == socket.AF_INET:  # IPv4
                self.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL,
                                ttl_bin)
                self.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
            else:  # IPv6
                self.setsockopt(socket.IPPROTO_IPV6,
                                socket.IPV6_MULTICAST_HOPS, ttl_bin)
                self.setsockopt(socket.IPPROTO_IPV6,
                                socket.IPV6_MULTICAST_LOOP, 1)

            # Bind to the port
            try:
                # bind to default interfaces if not unicast socket was created
                to_group = self.mgroup if self.unicast_socket is not None else ''
                self.bind((to_group, port))
            except socket.error as errobj:
                msg = str(errobj)
                rospy.logfatal(
                    "Unable to bind multicast to interface: %s, check that it exists: %s",
                    self.mgroup, msg)
                raise

            self.join_group()

        if not self.unicast_only:
            # create a thread to handle the received multicast messages
            self._recv_thread = threading.Thread(
                target=self.recv_loop_multicast)
            self._recv_thread.start()
        if self.unicast_socket is not None:
            # create a thread to handle the received unicast messages
            self._recv_thread = threading.Thread(target=self.recv_loop_unicast)
            self._recv_thread.start()
        self._send_tread = threading.Thread(target=self._send_loop_from_queue)
        self._send_tread.start()