Line data Source code
1 : /*
2 : * Host.cxx
3 : * OksSystem
4 : *
5 : * Created by Matthias Wiesmann on 03.02.05.
6 : * Copyright 2005 CERN. All rights reserved.
7 : *
8 : */
9 :
10 :
11 : #include <sys/types.h>
12 : #include <sys/socket.h>
13 : #include <sys/utsname.h>
14 : #include <netdb.h>
15 :
16 : #include <unistd.h>
17 :
18 : #include <iostream>
19 : #include <sstream>
20 : #include <strings.h>
21 :
22 : #include "okssystem/Host.hpp"
23 :
24 : #define BUFFER_SIZE 256
25 :
26 : /** Translates an hostname into an ip address
27 : * \param name hostname to translate
28 : * \return the ip addrress, 0.0.0.0 if name not found.
29 : * \note only returns the first ip address associated with name
30 : */
31 :
32 16 : struct sockaddr_in OksSystem::Host::resolve(const std::string &name) throw() {
33 16 : struct addrinfo *info_ptr;
34 16 : const char *str = name.c_str();
35 16 : const int status = getaddrinfo(str,0,0,&info_ptr);
36 16 : struct sockaddr_in address;
37 16 : bzero(&address,sizeof(address));
38 16 : address.sin_family = AF_INET;
39 16 : address.sin_addr.s_addr=0;
40 16 : if (status==0) {
41 16 : struct sockaddr_in *ptr = (sockaddr_in *) info_ptr->ai_addr;
42 16 : address = *ptr;
43 16 : freeaddrinfo(info_ptr);
44 : } // if
45 16 : return address;
46 : } // resolve
47 :
48 : /** Translates an ip address into an hostname
49 : * \param address the address to translate
50 : * \return the hostname an empty string if the hostname could not be resolved
51 : */
52 :
53 16 : std::string OksSystem::Host::resolve(struct sockaddr_in address) throw() {
54 16 : char buffer[NI_MAXHOST];
55 16 : const struct sockaddr *ptr = (const struct sockaddr *) &address;
56 16 : const int status= getnameinfo(ptr,sizeof(address),buffer,sizeof(buffer),0,0,0);
57 16 : if (status!=0) return to_string(address);
58 16 : return std::string(buffer);
59 : } // resolve
60 :
61 : /** Tries to build a fully qualified name.
62 : * This is done first by converting the name to ip then the ip to a name.
63 : * If this fails (basically, we cannot do DNS resolves)
64 : * the non fully qualified name is returned
65 : * \param name the (partial) name
66 : * \return fullname
67 : */
68 :
69 16 : std::string OksSystem::Host::expand(const std::string &name) throw() {
70 16 : const struct sockaddr_in address = resolve(name);
71 16 : if (address.sin_addr.s_addr!=0) return resolve(address);
72 0 : return std::string(name) ;
73 : } // expand
74 :
75 : /** Transliterate an ip address into the canonical dotted text version (w.x.y.z).
76 : * \param ip_addr the address to translate
77 : * \return string containing the text version
78 : * \note Should use addr2ascii
79 : */
80 :
81 0 : std::string OksSystem::Host::to_string(struct sockaddr_in ip_addr) {
82 0 : const char* s = inet_ntoa(ip_addr.sin_addr);
83 0 : return std::string(s);
84 : } // to_string
85 :
86 : // Constructors, destructors
87 : // --------------------------
88 :
89 : /** Constructors for the local host
90 : */
91 :
92 16 : OksSystem::Host::Host() throw() {} // Host
93 :
94 0 : OksSystem::Host::Host(const OksSystem::Host &other) {
95 0 : m_name = other.m_name;
96 0 : if (! other.m_full_name.empty()) {
97 0 : m_full_name = other.m_full_name;
98 : } // if
99 0 : } // Host
100 :
101 :
102 : /** Constructor for host by name
103 : * \param name name of the host
104 : */
105 :
106 0 : OksSystem::Host::Host(const std::string &s_name) {
107 0 : m_name = s_name;
108 0 : } // Host
109 :
110 :
111 0 : OksSystem::Host::Host(struct sockaddr_in ip_addr) {
112 0 : m_name = resolve(ip_addr);
113 0 : m_full_name = m_name;
114 0 : } // Host
115 :
116 :
117 0 : OksSystem::Host::~Host() throw() {
118 0 : } // OksSystem
119 :
120 : // Operator
121 : // --------------------------
122 :
123 : /** Cast conversion into ip address
124 : * \return ip address
125 : */
126 :
127 0 : OksSystem::Host::operator struct sockaddr_in() const throw() {
128 0 : return ip();
129 : } // struct sockaddr_in
130 :
131 : /** Comparison method
132 : * We try to expand both name and compare those
133 : * \param other the host to compare to
134 : * \return \c true if both have the same fully qualified name
135 : */
136 :
137 0 : bool OksSystem::Host::equals(const Host &other) const throw() {
138 0 : return full_name()==other.full_name();
139 : } // equals
140 :
141 :
142 : // Methods
143 : // --------------------------
144 :
145 : /** Name (this might be non fully qualified name)
146 : * \return name of the host
147 : */
148 :
149 0 : const std::string & OksSystem::Host::name() const throw() { return m_name;}
150 :
151 : /** IP address of the host
152 : * \return IP address of the host, or 0.0.0.0 if it cannot be resolved
153 : */
154 :
155 0 : struct sockaddr_in OksSystem::Host::ip() const throw() { return resolve(m_name);}
156 :
157 : /** Fully qualified name of the host
158 : * \return Fully qualified name of the host, or the string \"0.0.0.0\"
159 : */
160 :
161 16 : const std::string & OksSystem::Host::full_name() const throw() {
162 16 : if (m_full_name.empty()) {
163 16 : m_full_name = expand(m_name);
164 : } // if
165 16 : return m_full_name;
166 : } // full_name
167 :
168 : /** The IP Address of the host, as a string
169 : * \return a string containing the IP address of the host in w.x.y.z format
170 : */
171 :
172 0 : std::string OksSystem::Host::ip_string() const throw() {
173 0 : const struct sockaddr_in address = ip();
174 0 : return to_string(address);
175 : } // ip_string
176 :
177 :
178 :
179 0 : bool OksSystem::operator ==(const Host &a, const Host &b) throw() {
180 0 : return a.equals(b);
181 : } // operator ==
182 :
183 0 : bool OksSystem::operator !=(const Host &a, const Host &b) throw() {
184 0 : return ! a.equals(b);
185 : } // operator ≠
186 :
187 : // Local Host
188 : // --------------------------
189 :
190 : /** Instance of local host
191 : * \brief LocalHost singleton
192 : */
193 :
194 : OksSystem::LocalHost* OksSystem::LocalHost::s_instance = 0;
195 :
196 : /** Short-cut method - gives the local hostname
197 : * This name is not guaranteed to be a fully qualified name.
198 : * \return hostname
199 : * \see OksSystem::LocalHost::name()
200 : */
201 :
202 0 : const std::string & OksSystem::LocalHost::local_name() throw() {
203 0 : return instance()->name();
204 : } // localhostname
205 :
206 : /** Short-cut method - gives the fully qualified local hostname
207 : * \return fully qualified hostname
208 : * \see OksSystem::LocalHost::full_name()
209 : */
210 :
211 16 : const std::string & OksSystem::LocalHost::full_local_name() throw() {
212 16 : return instance()->full_name();
213 : } // fulllocalhostname
214 :
215 : /** This method returns a pointer to the singleton instance.
216 : * There is no need to ever create any instance of LocalHost
217 : * \return pointer to singleton instance
218 : * \note utility methods like \c full_local_name use this instance class
219 : */
220 :
221 32 : const OksSystem::LocalHost* OksSystem::LocalHost::instance() throw() {
222 32 : if (0==s_instance) {
223 16 : s_instance = new LocalHost();
224 : } //
225 32 : return s_instance;
226 : } // instance
227 :
228 : /** Constructor
229 : * You should \b not construct new instances, use \c instance to get the
230 : * singleton instance.
231 : */
232 :
233 16 : OksSystem::LocalHost::LocalHost() throw() : Host() {
234 16 : struct utsname u_name_data;
235 16 : const int status = ::uname(&u_name_data);
236 16 : if (status==0) {
237 16 : m_name = u_name_data.nodename;
238 16 : m_os_name = u_name_data.sysname;
239 16 : m_release = u_name_data.release;
240 16 : m_version = u_name_data.version;
241 16 : m_machine = u_name_data.machine;
242 : } else {
243 0 : char buffer[NI_MAXHOST];
244 0 : const int host_status = gethostname(buffer,sizeof(buffer));
245 0 : if (host_status==0) {
246 0 : m_name = buffer;
247 : } else { // both uname and gethostname screwed
248 0 : m_name.clear();
249 : } // check for host_name
250 : } // uname failed.
251 16 : } // LocalHost
252 :
253 0 : OksSystem::LocalHost::~LocalHost() throw() {
254 : // delete s_instance;
255 0 : }
256 :
257 : /** \return Operating OksSystem name */
258 :
259 0 : const std::string & OksSystem::LocalHost::os_name() const throw() {
260 0 : return m_os_name;
261 : } // os_name
262 :
263 : /** \return Operating OksSystem release */
264 :
265 0 : const std::string & OksSystem::LocalHost::os_release() const throw() {
266 0 : return m_release;
267 : } // os_release
268 :
269 : /** \return Operating OksSystem version */
270 :
271 0 : const std::string & OksSystem::LocalHost::os_version() const throw() {
272 0 : return m_version;
273 : } // os_version
274 :
275 : /** \return machine name */
276 :
277 0 : const std::string & OksSystem::LocalHost::machine() const throw() {
278 0 : return m_machine;
279 : } // machine
280 :
281 : /** This method builds a description of the localhost
282 : * This contains all the of the information handled by this class.
283 : * \return description text
284 : */
285 :
286 0 : const std::string & OksSystem::LocalHost::description() const throw() {
287 0 : if (m_description.empty()) {
288 0 : std::ostringstream stream;
289 0 : stream << m_os_name << " " << m_release << "/" << m_machine;
290 0 : m_description = stream.str();
291 0 : }
292 0 : return m_description;
293 : } // description
294 :
295 : /** Convenience method, finds the fully qualified host name for this node
296 : * \return c-string with fully qualified hostname
297 : * \note the string is owned by the singleton object it should not be deleted
298 : * \note if resolve fails (typically because there is no network) this method might return
299 : * the short (unqualified) host name.
300 : */
301 :
302 0 : const char* OksSystem::getfullhost() throw() {
303 0 : const std::string & str = OksSystem::LocalHost::full_local_name();
304 0 : return str.c_str();
305 : } // full_host_name
306 :
307 : /** Comparison operator
308 : * Simple optimisation - if we compare two localhost instances, they are always equal
309 : * \param a first instance
310 : * \param b second instance
311 : */
312 :
313 0 : bool OksSystem::operator ==(const LocalHost &, const LocalHost & ) throw()
314 : {
315 0 : return true;
316 : }
317 :
318 : /** Comparison operator
319 : * Simple optimisation - if we compare two localhost instances, they are always equal
320 : * \param a first instance
321 : * \param b second instance
322 : */
323 :
324 0 : bool OksSystem::operator !=(const LocalHost &, const LocalHost & ) throw()
325 : {
326 0 : return false;
327 : }
328 :
329 0 : std::ostream& operator<<(std::ostream& stream, const OksSystem::Host& host) {
330 0 : stream << host.full_name();
331 0 : return stream;
332 : } // operator<<
333 :
334 :
335 :
|