00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "config.h"
00029 #include "ros/network.h"
00030 #include "ros/file_log.h"
00031 #include "ros/exceptions.h"
00032
00033 #include <ros/console.h>
00034 #include <ros/assert.h>
00035
00036 #include <netinet/in.h>
00037 #include <sys/socket.h>
00038 #include <netdb.h>
00039
00040 #ifdef HAVE_IFADDRS_H
00041 #include <ifaddrs.h>
00042 #endif
00043
00044 #include <boost/lexical_cast.hpp>
00045
00046 namespace ros
00047 {
00048
00049 namespace network
00050 {
00051
00052 std::string g_host;
00053 uint16_t g_tcpros_server_port = 0;
00054
00055 const std::string& getHost()
00056 {
00057 return g_host;
00058 }
00059
00060 bool splitURI(const std::string& uri, std::string& host, uint32_t& port)
00061 {
00062
00063 if (uri.substr(0, 7) == std::string("http://"))
00064 host = uri.substr(7);
00065 else if (uri.substr(0, 9) == std::string("rosrpc://"))
00066 host = uri.substr(9);
00067
00068 std::string::size_type colon_pos = host.find_first_of(":");
00069 if (colon_pos == std::string::npos)
00070 return false;
00071 std::string port_str = host.substr(colon_pos+1);
00072 std::string::size_type slash_pos = port_str.find_first_of("/");
00073 if (slash_pos != std::string::npos)
00074 port_str = port_str.erase(slash_pos);
00075 port = atoi(port_str.c_str());
00076 host = host.erase(colon_pos);
00077 return true;
00078 }
00079
00080 uint16_t getTCPROSPort()
00081 {
00082 return g_tcpros_server_port;
00083 }
00084
00085 static bool isPrivateIP(const char *ip)
00086 {
00087 bool b = !strncmp("192.168", ip, 7) || !strncmp("10.", ip, 3) ||
00088 !strncmp("169.254", ip, 7);
00089 return b;
00090 }
00091
00092 std::string determineHost()
00093 {
00094
00095 char *ip_env = getenv("ROS_HOSTNAME");
00096 if (ip_env)
00097 {
00098 ROSCPP_LOG_DEBUG( "determineIP: using value of ROS_HOSTNAME:%s:", ip_env);
00099 return std::string(ip_env);
00100 }
00101
00102
00103 ip_env = getenv("ROS_IP");
00104 if (ip_env)
00105 {
00106 ROSCPP_LOG_DEBUG( "determineIP: using value of ROS_IP:%s:", ip_env);
00107 return std::string(ip_env);
00108 }
00109
00110
00111 char host[1024];
00112 memset(host,0,sizeof(host));
00113 if(gethostname(host,sizeof(host)-1) != 0)
00114 {
00115 ROS_ERROR("determineIP: gethostname failed");
00116 }
00117
00118 else if(strlen(host) && strcmp("localhost", host))
00119 {
00120 return std::string(host);
00121 }
00122
00123
00124
00125 #ifdef HAVE_IFADDRS_H
00126 struct ifaddrs *ifa = NULL, *ifp = NULL;
00127 int rc;
00128 if ((rc = getifaddrs(&ifp)) < 0)
00129 {
00130 ROS_FATAL("error in getifaddrs: [%s]", strerror(rc));
00131 ROS_BREAK();
00132 }
00133 char preferred_ip[200] = {0};
00134 for (ifa = ifp; ifa; ifa = ifa->ifa_next)
00135 {
00136 char ip_[200];
00137 socklen_t salen;
00138 if (!ifa->ifa_addr)
00139 continue;
00140 if (ifa->ifa_addr->sa_family == AF_INET)
00141 salen = sizeof(struct sockaddr_in);
00142 else if (ifa->ifa_addr->sa_family == AF_INET6)
00143 salen = sizeof(struct sockaddr_in6);
00144 else
00145 continue;
00146 if (getnameinfo(ifa->ifa_addr, salen, ip_, sizeof(ip_), NULL, 0,
00147 NI_NUMERICHOST) < 0)
00148 {
00149 ROSCPP_LOG_DEBUG( "getnameinfo couldn't get the ip of interface [%s]", ifa->ifa_name);
00150 continue;
00151 }
00152
00153
00154 if (!strcmp("127.0.0.1", ip_) || strchr(ip_,':'))
00155 continue;
00156 if (ifa->ifa_addr->sa_family == AF_INET6 && !preferred_ip[0])
00157 strcpy(preferred_ip, ip_);
00158 else if (isPrivateIP(ip_) && !preferred_ip[0])
00159 strcpy(preferred_ip, ip_);
00160 else if (!isPrivateIP(ip_) &&
00161 (isPrivateIP(preferred_ip) || !preferred_ip[0]))
00162 strcpy(preferred_ip, ip_);
00163 }
00164 freeifaddrs(ifp);
00165 if (!preferred_ip[0])
00166 {
00167 ROS_ERROR( "Couldn't find a preferred IP via the getifaddrs() call; I'm assuming that your IP "
00168 "address is 127.0.0.1. This should work for local processes, "
00169 "but will almost certainly not work if you have remote processes."
00170 "Report to the ROS development team to seek a fix.");
00171 return std::string("127.0.0.1");
00172 }
00173 ROSCPP_LOG_DEBUG( "preferred IP is guessed to be %s", preferred_ip);
00174 return std::string(preferred_ip);
00175 #else
00176
00177
00178 ROS_ERROR( "You don't have the getifaddrs() call; I'm assuming that your IP "
00179 "address is 127.0.0.1. This should work for local processes, "
00180 "but will almost certainly not work if you have remote processes."
00181 "Report to the ROS development team to seek a fix.");
00182 return std::string("127.0.0.1");
00183 #endif
00184 }
00185
00186 void init(const M_string& remappings)
00187 {
00188 M_string::const_iterator it = remappings.find("__hostname");
00189 if (it != remappings.end())
00190 {
00191 g_host = it->second;
00192 }
00193 else
00194 {
00195 it = remappings.find("__ip");
00196 if (it != remappings.end())
00197 {
00198 g_host = it->second;
00199 }
00200 }
00201
00202 it = remappings.find("__tcpros_server_port");
00203 if (it != remappings.end())
00204 {
00205 try
00206 {
00207 g_tcpros_server_port = boost::lexical_cast<uint16_t>(it->second);
00208 }
00209 catch (boost::bad_lexical_cast&)
00210 {
00211 throw ros::InvalidPortException("__tcpros_server_port [" + it->second + "] was not specified as a number within the 0-65535 range");
00212 }
00213 }
00214
00215 if (g_host.empty())
00216 {
00217 g_host = determineHost();
00218 }
00219 }
00220
00221 }
00222
00223 }