Reputation: 8313
I wrote a program to get local host name. if it is not obvious, I mean to get the host name of the local machine similar to gethostname
method, not to get the string localhost
I'm using getaddrinfo
with NULL
for host name and then call to getnameinfo
with the first address.
It works perfectly on windows machines, and giving me the canonical host name, but in Linux it failed to give me the local host name and gives me ::
for IPv6 or 0.0.0.0
for IPv4.
Note that I'm using AI_PASSIVE
flag in getaddrinfo
, means it gives me no more than two addresses.
In the getnameinfo
if I use the NI_NAMEREQD
it fail.
I'm doing so because I have a server, sometimes I want to listen to all interfaces and sometimes to a specific interface, I'm already have the addrinfo
and I just want to get the hostname from it if possible.
How can I make it work on Linux? did I missed anything?
Thanks for any help.
Here is my code: (cross platform, windows and Linux, just copy & past) You can compile and run on both and see the difference.
#include <iostream>
#ifdef WIN32
#ifdef UNICODE
#undef UNICODE /* don't want Unicode, to keep code compatibility */
#endif
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
class CWSAInitializer{
public:
CWSAInitializer(){
WSADATA data;
WSAStartup(MAKEWORD(2,2),&data);
}
~CWSAInitializer(){
WSACleanup();
}
}autoInit;
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#endif
const char* get_hostname(struct addrinfo* info, char buff[], int buff_len)
{
int addrlen = (int)info->ai_addrlen;
int res = getnameinfo(info->ai_addr, addrlen, buff, buff_len, NULL, 0, 0);
if(res){
return NULL;
}
return buff;
}
int main ()
{
char temp[100];
addrinfo *ai,hints;
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_flags |= AI_PASSIVE;
int res = getaddrinfo(NULL, "0", &hints, &ai);
if(res){
std::cerr<<gai_strerror(res)<<std::endl;
return -1;
}
std::cout<< get_hostname(ai,temp,100)<<std::endl;
freeaddrinfo(ai);
return 0;
}
EDIT
The server should accept client from other machines as well, so it can't report listening on ::
or 0.0.0.0
.
I know I can patch it like this:
if(std::string("::") == hostname || std::string("0.0.0.0") == hostname)
gethostname(hostname,100)
localhost
as result, unless the address is 127.0.0.1
or ::1
.Upvotes: 1
Views: 1308
Reputation: 70911
getaddrinfo()
returns the head of list of struct addrinfo
nodes.
Travers this list using struct addrinfo
's a member ai_next
to find the addresses of all interfaces of the machine.
To receive anything else but wildcard addresses do not specify the AI_PASSIVE
flag in the hints passed.
Update on the various names given to a machine and/or its interfaces' addresses:
The host's name ("hostname") as returend by gethostname()
is an attribute to the host. It is configured on the host and not held in any external database. This host name per definition is not linked to any of the names the possible interfaces' addresses resolve to. The host name might however be configured to match the name that one of the addresses (of the interfaces of the machine) resolves to.
There might be more then one interface provided by a machine. Each of these interfaces' address should resolves to a different name, which in turn could also all differ from the name returned by gethostname()
(see 1. above). This applies to all types of interfaces including IPv4 and IPv6. There also it the virtual wildcard-address (0.0.0.0
for IPv4) which allows programs to bind to and listen on all interfaces (IPv4 typed here) a machine provides. The wildcard-adresse has no name.
The conclusion from 1. and 2. is: There is no name "... like [returned by] gethostname() but canonical."!
Upvotes: 1