blob: ea7f521f2b1408b73794401bb4e60165c71c1068 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
#include "qpid/log/Statement.h"
#include "qpid/sys/SystemInfo.h"
#include "qpid/sys/posix/check.h"
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <sys/types.h> // For FreeBSD
#include <sys/socket.h> // For FreeBSD
#include <netinet/in.h> // For FreeBSD
#include <ifaddrs.h>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <map>
#include <netdb.h>
#include <string.h>
#ifndef HOST_NAME_MAX
# define HOST_NAME_MAX 256
#endif
using namespace std;
namespace qpid {
namespace sys {
long SystemInfo::concurrency() {
#ifdef _SC_NPROCESSORS_ONLN // Linux specific.
return sysconf(_SC_NPROCESSORS_ONLN);
#else
return -1;
#endif
}
bool SystemInfo::getLocalHostname (Address &address) {
char name[HOST_NAME_MAX];
if (::gethostname(name, sizeof(name)) != 0)
return false;
address.host = name;
return true;
}
static const string LOOPBACK("127.0.0.1");
static const string TCP("tcp");
// Test IPv4 address for loopback
inline bool IN_IS_ADDR_LOOPBACK(const ::in_addr* a) {
return ((ntohl(a->s_addr) & 0xff000000) == 0x7f000000);
}
inline bool isLoopback(const ::sockaddr* addr) {
switch (addr->sa_family) {
case AF_INET: return IN_IS_ADDR_LOOPBACK(&((const ::sockaddr_in*)(const void*)addr)->sin_addr);
case AF_INET6: return IN6_IS_ADDR_LOOPBACK(&((const ::sockaddr_in6*)(const void*)addr)->sin6_addr);
default: return false;
}
}
namespace {
inline socklen_t sa_len(::sockaddr* sa)
{
switch (sa->sa_family) {
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
default:
return sizeof(struct sockaddr_storage);
}
}
inline bool isInetOrInet6(::sockaddr* sa) {
switch (sa->sa_family) {
case AF_INET:
case AF_INET6:
return true;
default:
return false;
}
}
typedef std::map<std::string, std::vector<std::string> > InterfaceInfo;
std::map<std::string, std::vector<std::string> > cachedInterfaces;
void cacheInterfaceInfo() {
// Get interface info
::ifaddrs* interfaceInfo;
QPID_POSIX_CHECK( ::getifaddrs(&interfaceInfo) );
char name[NI_MAXHOST];
for (::ifaddrs* info = interfaceInfo; info != 0; info = info->ifa_next) {
// Only use IPv4/IPv6 interfaces
if (!isInetOrInet6(info->ifa_addr)) continue;
int rc=::getnameinfo(info->ifa_addr, sa_len(info->ifa_addr),
name, sizeof(name), 0, 0,
NI_NUMERICHOST);
if (rc >= 0) {
std::string address(name);
cachedInterfaces[info->ifa_name].push_back(address);
} else {
throw qpid::Exception(QPID_MSG(gai_strerror(rc)));
}
}
::freeifaddrs(interfaceInfo);
}
}
bool SystemInfo::getInterfaceAddresses(const std::string& interface, std::vector<std::string>& addresses) {
if ( cachedInterfaces.empty() ) cacheInterfaceInfo();
InterfaceInfo::iterator i = cachedInterfaces.find(interface);
if ( i==cachedInterfaces.end() ) return false;
std::copy(i->second.begin(), i->second.end(), std::back_inserter(addresses));
return true;
}
void SystemInfo::getInterfaceNames(std::vector<std::string>& names ) {
if ( cachedInterfaces.empty() ) cacheInterfaceInfo();
for (InterfaceInfo::const_iterator i = cachedInterfaces.begin(); i!=cachedInterfaces.end(); ++i) {
names.push_back(i->first);
}
}
void SystemInfo::getSystemId (std::string &osName,
std::string &nodeName,
std::string &release,
std::string &version,
std::string &machine)
{
struct utsname _uname;
if (uname (&_uname) == 0)
{
osName = _uname.sysname;
nodeName = _uname.nodename;
release = _uname.release;
version = _uname.version;
machine = _uname.machine;
}
}
uint32_t SystemInfo::getProcessId()
{
return (uint32_t) ::getpid();
}
uint32_t SystemInfo::getParentProcessId()
{
return (uint32_t) ::getppid();
}
// Linux specific (Solaris has quite different stuff in /proc)
string SystemInfo::getProcessName()
{
string value;
ifstream input("/proc/self/status");
if (input.good()) {
while (!input.eof()) {
string key;
input >> key;
if (key == "Name:") {
input >> value;
break;
}
}
input.close();
}
return value;
}
// Always true. Only Windows has exception cases.
bool SystemInfo::threadSafeShutdown()
{
return true;
}
}} // namespace qpid::sys