$search
00001 /* 00002 * Copyright (C) 2009, Willow Garage, Inc. 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions are met: 00006 * * Redistributions of source code must retain the above copyright notice, 00007 * this list of conditions and the following disclaimer. 00008 * * Redistributions in binary form must reproduce the above copyright 00009 * notice, this list of conditions and the following disclaimer in the 00010 * documentation and/or other materials provided with the distribution. 00011 * * Neither the names of Stanford University or Willow Garage, Inc. nor the names of its 00012 * contributors may be used to endorse or promote products derived from 00013 * this software without specific prior written permission. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00016 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00017 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00019 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00020 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00021 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00023 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00024 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00025 * POSSIBILITY OF SUCH DAMAGE. 00026 */ 00027 00028 #include "config.h" 00029 #include "ros/network.h" 00030 #include "ros/file_log.h" 00031 #include "ros/exceptions.h" 00032 #include "ros/io.h" // cross-platform headers needed 00033 #include <ros/console.h> 00034 #include <ros/assert.h> 00035 #ifdef HAVE_IFADDRS_H 00036 #include <ifaddrs.h> 00037 #endif 00038 00039 #include <boost/lexical_cast.hpp> 00040 00041 namespace ros 00042 { 00043 00044 namespace network 00045 { 00046 00047 std::string g_host; 00048 uint16_t g_tcpros_server_port = 0; 00049 00050 const std::string& getHost() 00051 { 00052 return g_host; 00053 } 00054 00055 bool splitURI(const std::string& uri, std::string& host, uint32_t& port) 00056 { 00057 // skip over the protocol if it's there 00058 if (uri.substr(0, 7) == std::string("http://")) 00059 host = uri.substr(7); 00060 else if (uri.substr(0, 9) == std::string("rosrpc://")) 00061 host = uri.substr(9); 00062 // split out the port 00063 std::string::size_type colon_pos = host.find_first_of(":"); 00064 if (colon_pos == std::string::npos) 00065 return false; 00066 std::string port_str = host.substr(colon_pos+1); 00067 std::string::size_type slash_pos = port_str.find_first_of("/"); 00068 if (slash_pos != std::string::npos) 00069 port_str = port_str.erase(slash_pos); 00070 port = atoi(port_str.c_str()); 00071 host = host.erase(colon_pos); 00072 return true; 00073 } 00074 00075 uint16_t getTCPROSPort() 00076 { 00077 return g_tcpros_server_port; 00078 } 00079 00080 static bool isPrivateIP(const char *ip) 00081 { 00082 bool b = !strncmp("192.168", ip, 7) || !strncmp("10.", ip, 3) || 00083 !strncmp("169.254", ip, 7); 00084 return b; 00085 } 00086 00087 std::string determineHost() 00088 { 00089 std::string ip_env; 00090 // First, did the user set ROS_HOSTNAME? 00091 if ( get_environment_variable(ip_env, "ROS_HOSTNAME")) { 00092 ROSCPP_LOG_DEBUG( "determineIP: using value of ROS_HOSTNAME:%s:", ip_env.c_str()); 00093 return ip_env; 00094 } 00095 00096 // Second, did the user set ROS_IP? 00097 if ( get_environment_variable(ip_env, "ROS_IP")) { 00098 ROSCPP_LOG_DEBUG( "determineIP: using value of ROS_IP:%s:", ip_env.c_str()); 00099 return ip_env; 00100 } 00101 00102 // Third, try the hostname 00103 char host[1024]; 00104 memset(host,0,sizeof(host)); 00105 if(gethostname(host,sizeof(host)-1) != 0) 00106 { 00107 ROS_ERROR("determineIP: gethostname failed"); 00108 } 00109 // We don't want localhost to be our ip 00110 else if(strlen(host) && strcmp("localhost", host)) 00111 { 00112 return std::string(host); 00113 } 00114 00115 // Fourth, fall back on interface search, which will yield an IP address 00116 00117 #ifdef HAVE_IFADDRS_H 00118 struct ifaddrs *ifa = NULL, *ifp = NULL; 00119 int rc; 00120 if ((rc = getifaddrs(&ifp)) < 0) 00121 { 00122 ROS_FATAL("error in getifaddrs: [%s]", strerror(rc)); 00123 ROS_BREAK(); 00124 } 00125 char preferred_ip[200] = {0}; 00126 for (ifa = ifp; ifa; ifa = ifa->ifa_next) 00127 { 00128 char ip_[200]; 00129 socklen_t salen; 00130 if (!ifa->ifa_addr) 00131 continue; // evidently this interface has no ip address 00132 if (ifa->ifa_addr->sa_family == AF_INET) 00133 salen = sizeof(struct sockaddr_in); 00134 else if (ifa->ifa_addr->sa_family == AF_INET6) 00135 salen = sizeof(struct sockaddr_in6); 00136 else 00137 continue; 00138 if (getnameinfo(ifa->ifa_addr, salen, ip_, sizeof(ip_), NULL, 0, 00139 NI_NUMERICHOST) < 0) 00140 { 00141 ROSCPP_LOG_DEBUG( "getnameinfo couldn't get the ip of interface [%s]", ifa->ifa_name); 00142 continue; 00143 } 00144 //ROS_INFO( "ip of interface [%s] is [%s]", ifa->ifa_name, ip); 00145 // prefer non-private IPs over private IPs 00146 if (!strcmp("127.0.0.1", ip_) || strchr(ip_,':')) 00147 continue; // ignore loopback unless we have no other choice 00148 if (ifa->ifa_addr->sa_family == AF_INET6 && !preferred_ip[0]) 00149 strcpy(preferred_ip, ip_); 00150 else if (isPrivateIP(ip_) && !preferred_ip[0]) 00151 strcpy(preferred_ip, ip_); 00152 else if (!isPrivateIP(ip_) && 00153 (isPrivateIP(preferred_ip) || !preferred_ip[0])) 00154 strcpy(preferred_ip, ip_); 00155 } 00156 freeifaddrs(ifp); 00157 if (!preferred_ip[0]) 00158 { 00159 ROS_ERROR( "Couldn't find a preferred IP via the getifaddrs() call; I'm assuming that your IP " 00160 "address is 127.0.0.1. This should work for local processes, " 00161 "but will almost certainly not work if you have remote processes." 00162 "Report to the ROS development team to seek a fix."); 00163 return std::string("127.0.0.1"); 00164 } 00165 ROSCPP_LOG_DEBUG( "preferred IP is guessed to be %s", preferred_ip); 00166 return std::string(preferred_ip); 00167 #else 00168 // @todo Fix IP determination in the case where getifaddrs() isn't 00169 // available. 00170 ROS_ERROR( "You don't have the getifaddrs() call; I'm assuming that your IP " 00171 "address is 127.0.0.1. This should work for local processes, " 00172 "but will almost certainly not work if you have remote processes." 00173 "Report to the ROS development team to seek a fix."); 00174 return std::string("127.0.0.1"); 00175 #endif 00176 } 00177 00178 void init(const M_string& remappings) 00179 { 00180 M_string::const_iterator it = remappings.find("__hostname"); 00181 if (it != remappings.end()) 00182 { 00183 g_host = it->second; 00184 } 00185 else 00186 { 00187 it = remappings.find("__ip"); 00188 if (it != remappings.end()) 00189 { 00190 g_host = it->second; 00191 } 00192 } 00193 00194 it = remappings.find("__tcpros_server_port"); 00195 if (it != remappings.end()) 00196 { 00197 try 00198 { 00199 g_tcpros_server_port = boost::lexical_cast<uint16_t>(it->second); 00200 } 00201 catch (boost::bad_lexical_cast&) 00202 { 00203 throw ros::InvalidPortException("__tcpros_server_port [" + it->second + "] was not specified as a number within the 0-65535 range"); 00204 } 00205 } 00206 00207 if (g_host.empty()) 00208 { 00209 g_host = determineHost(); 00210 } 00211 } 00212 00213 } // namespace network 00214 00215 } // namespace ros